spree_storefront 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/Rakefile +15 -0
- data/app/assets/config/spree_storefront_manifest.js +6 -0
- data/app/assets/stylesheets/storefront_page_builder.css +51 -0
- data/app/controllers/concerns/spree/cart_methods.rb +40 -0
- data/app/controllers/concerns/spree/locale_urls.rb +23 -0
- data/app/controllers/concerns/spree/password_protected.rb +17 -0
- data/app/controllers/concerns/spree/theme_concern.rb +29 -0
- data/app/controllers/spree/account/addresses_controller.rb +16 -0
- data/app/controllers/spree/account/base_controller.rb +20 -0
- data/app/controllers/spree/account/newsletter_controller.rb +34 -0
- data/app/controllers/spree/account/orders_controller.rb +34 -0
- data/app/controllers/spree/account/profile_controller.rb +23 -0
- data/app/controllers/spree/account/store_credits_controller.rb +23 -0
- data/app/controllers/spree/account/wished_items_controller.rb +45 -0
- data/app/controllers/spree/addresses_controller.rb +101 -0
- data/app/controllers/spree/checkout_controller.rb +365 -0
- data/app/controllers/spree/contacts_controller.rb +46 -0
- data/app/controllers/spree/digital_links_controller.rb +48 -0
- data/app/controllers/spree/home_controller.rb +5 -0
- data/app/controllers/spree/line_items_controller.rb +96 -0
- data/app/controllers/spree/newsletter_subscribers_controller.rb +43 -0
- data/app/controllers/spree/order_status_controller.rb +32 -0
- data/app/controllers/spree/orders_controller.rb +104 -0
- data/app/controllers/spree/page_sections_controller.rb +17 -0
- data/app/controllers/spree/pages_controller.rb +13 -0
- data/app/controllers/spree/password_controller.rb +21 -0
- data/app/controllers/spree/policies_controller.rb +17 -0
- data/app/controllers/spree/posts_controller.rb +76 -0
- data/app/controllers/spree/products_controller.rb +99 -0
- data/app/controllers/spree/search_controller.rb +39 -0
- data/app/controllers/spree/seo_controller.rb +25 -0
- data/app/controllers/spree/settings_controller.rb +68 -0
- data/app/controllers/spree/store_controller.rb +247 -0
- data/app/controllers/spree/taxonomies_controller.rb +30 -0
- data/app/controllers/spree/taxons_controller.rb +46 -0
- data/app/controllers/spree/wishlists_controller.rb +19 -0
- data/app/finders/spree/storefront/variant_finder.rb +80 -0
- data/app/helpers/spree/analytics_helper.rb +28 -0
- data/app/helpers/spree/cart_helper.rb +48 -0
- data/app/helpers/spree/checkout_analytics_helper.rb +77 -0
- data/app/helpers/spree/checkout_helper.rb +58 -0
- data/app/helpers/spree/filters_helper.rb +180 -0
- data/app/helpers/spree/fonts_helper.rb +58 -0
- data/app/helpers/spree/orders_helper.rb +7 -0
- data/app/helpers/spree/page_helper.rb +67 -0
- data/app/helpers/spree/posts_helper.rb +42 -0
- data/app/helpers/spree/products_helper.rb +205 -0
- data/app/helpers/spree/storefront_helper.rb +86 -0
- data/app/helpers/spree/storefront_locale_helper.rb +42 -0
- data/app/helpers/spree/theme_helper.rb +244 -0
- data/app/helpers/spree/turbo_helper.rb +13 -0
- data/app/helpers/spree/turbo_stream_actions_helper.rb +13 -0
- data/app/helpers/spree/wishlist_helper.rb +7 -0
- data/app/javascript/spree/storefront/application.js +156 -0
- data/app/javascript/spree/storefront/controllers/accordion_controller.js +25 -0
- data/app/javascript/spree/storefront/controllers/account_nav_controller.js +10 -0
- data/app/javascript/spree/storefront/controllers/card_validation_controller.js +103 -0
- data/app/javascript/spree/storefront/controllers/carousel_controller.js +44 -0
- data/app/javascript/spree/storefront/controllers/cart_controller.js +10 -0
- data/app/javascript/spree/storefront/controllers/checkout_address_book_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/checkout_delivery_controller.js +39 -0
- data/app/javascript/spree/storefront/controllers/checkout_promotions_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/checkout_summary_controller.js +46 -0
- data/app/javascript/spree/storefront/controllers/clear_input_controller.js +23 -0
- data/app/javascript/spree/storefront/controllers/copy_input_controller.js +19 -0
- data/app/javascript/spree/storefront/controllers/dropdown_controller.js +14 -0
- data/app/javascript/spree/storefront/controllers/header_controller.js +33 -0
- data/app/javascript/spree/storefront/controllers/infinite_scroll_controller.js +31 -0
- data/app/javascript/spree/storefront/controllers/lightbox_controller.js +138 -0
- data/app/javascript/spree/storefront/controllers/mobile_nav_controller.js +17 -0
- data/app/javascript/spree/storefront/controllers/modal_controller.js +15 -0
- data/app/javascript/spree/storefront/controllers/no_ui_slider_controller.js +55 -0
- data/app/javascript/spree/storefront/controllers/pdp_desktop_gallery_controller.js +28 -0
- data/app/javascript/spree/storefront/controllers/plp_variant_picker_controller.js +151 -0
- data/app/javascript/spree/storefront/controllers/product_form_controller.js +136 -0
- data/app/javascript/spree/storefront/controllers/quantity_picker_controller.js +43 -0
- data/app/javascript/spree/storefront/controllers/search_suggestions_controller.js +61 -0
- data/app/javascript/spree/storefront/controllers/searchable_list_controller.js +25 -0
- data/app/javascript/spree/storefront/controllers/slideover_controller.js +40 -0
- data/app/javascript/spree/storefront/controllers/sticky_button_controller.js +32 -0
- data/app/javascript/spree/storefront/controllers/toggle_menu_controller.js +32 -0
- data/app/javascript/spree/storefront/controllers/turbo_stream_form_controller.js +51 -0
- data/app/javascript/spree/storefront/controllers/wished_item_controller.js +69 -0
- data/app/javascript/spree/storefront/helpers/lazy_load_controllers_with_manifest.js +78 -0
- data/app/javascript/spree/storefront/helpers/show_flash_message.js +25 -0
- data/app/models/spree/color_names.rb +35 -0
- data/app/models/spree/contact.rb +24 -0
- data/app/presenters/spree/colors_preview_styles_presenter.rb +84 -0
- data/app/presenters/spree/featured_product_presenter.rb +42 -0
- data/app/presenters/spree/mega_nav_presenter.rb +55 -0
- data/app/views/devise/passwords/edit.html.erb +22 -0
- data/app/views/devise/passwords/new.html.erb +16 -0
- data/app/views/devise/registrations/_form.html.erb +21 -0
- data/app/views/devise/registrations/edit.html.erb +24 -0
- data/app/views/devise/registrations/new.html.erb +27 -0
- data/app/views/devise/sessions/new.html.erb +25 -0
- data/app/views/devise/shared/_links.html.erb +22 -0
- data/app/views/layouts/spree/checkout.html.erb +58 -0
- data/app/views/layouts/spree/password.html.erb +34 -0
- data/app/views/layouts/spree/storefront.html.erb +38 -0
- data/app/views/spree/account/wished_items/create.turbo_stream.erb +8 -0
- data/app/views/spree/account/wished_items/destroy.turbo_stream.erb +20 -0
- data/app/views/spree/addresses/destroy.turbo_stream.erb +1 -0
- data/app/views/spree/addresses/edit.html.erb +57 -0
- data/app/views/spree/addresses/new.html.erb +71 -0
- data/app/views/spree/checkout/_address.html.erb +153 -0
- data/app/views/spree/checkout/_button_processing.html.erb +7 -0
- data/app/views/spree/checkout/_coupon_code.html.erb +55 -0
- data/app/views/spree/checkout/_credit_card.html.erb +12 -0
- data/app/views/spree/checkout/_delivery.html.erb +70 -0
- data/app/views/spree/checkout/_line_item.html.erb +26 -0
- data/app/views/spree/checkout/_line_items.html.erb +7 -0
- data/app/views/spree/checkout/_missing_all_line_items.html.erb +17 -0
- data/app/views/spree/checkout/_missing_line_items.html.erb +28 -0
- data/app/views/spree/checkout/_payment.html.erb +35 -0
- data/app/views/spree/checkout/_payment_methods.html.erb +72 -0
- data/app/views/spree/checkout/_payment_sources.html.erb +24 -0
- data/app/views/spree/checkout/_quick_checkout.html.erb +1 -0
- data/app/views/spree/checkout/_sidebar.html.erb +34 -0
- data/app/views/spree/checkout/_store_credit.html.erb +21 -0
- data/app/views/spree/checkout/_summary.html.erb +116 -0
- data/app/views/spree/checkout/_user_account.html.erb +9 -0
- data/app/views/spree/checkout/apply_coupon_code.turbo_stream.erb +45 -0
- data/app/views/spree/checkout/apply_store_credit.turbo_stream.erb +19 -0
- data/app/views/spree/checkout/edit.html.erb +98 -0
- data/app/views/spree/checkout/payment/_check.html.erb +0 -0
- data/app/views/spree/checkout/payment/_gateway.html.erb +74 -0
- data/app/views/spree/checkout/payment/_store_credit.html.erb +13 -0
- data/app/views/spree/checkout/remove_coupon_code.turbo_stream.erb +34 -0
- data/app/views/spree/checkout/remove_store_credit.turbo_stream.erb +19 -0
- data/app/views/spree/checkout/update.turbo_stream.erb +25 -0
- data/app/views/spree/home/index.html.erb +1 -0
- data/app/views/spree/line_items/create.turbo_stream.erb +13 -0
- data/app/views/spree/line_items/destroy.turbo_stream.erb +11 -0
- data/app/views/spree/line_items/update.turbo_stream.erb +10 -0
- data/app/views/spree/newsletter_subscribers/create.turbo_stream.erb +7 -0
- data/app/views/spree/order_status/new.html.erb +16 -0
- data/app/views/spree/page_sections/show.html.erb +3 -0
- data/app/views/spree/pages/show.html.erb +1 -0
- data/app/views/spree/password/show.html.erb +1 -0
- data/app/views/spree/posts/index.html.erb +1 -0
- data/app/views/spree/posts/related_products.html.erb +7 -0
- data/app/views/spree/posts/show.html.erb +1 -0
- data/app/views/spree/products/index.html.erb +1 -0
- data/app/views/spree/products/index.turbo_stream.erb +1 -0
- data/app/views/spree/products/related.html.erb +3 -0
- data/app/views/spree/products/show.html.erb +1 -0
- data/app/views/spree/search/show.html.erb +6 -0
- data/app/views/spree/search/show.turbo_stream.erb +1 -0
- data/app/views/spree/search/suggestions.turbo_stream.erb +8 -0
- data/app/views/spree/seo/robots.text.erb +31 -0
- data/app/views/spree/seo/sitemap.xml.erb +25 -0
- data/app/views/spree/shared/_fonts.html.erb +14 -0
- data/app/views/spree/shared/_head.html.erb +36 -0
- data/app/views/spree/shared/_load_more_products.turbo_stream.erb +7 -0
- data/app/views/spree/shared/_product_listing_page.html.erb +11 -0
- data/app/views/spree/shared/_products.html.erb +1 -0
- data/app/views/spree/taxonomies/show.html.erb +1 -0
- data/app/views/spree/taxons/show.html.erb +1 -0
- data/app/views/spree/taxons/show.turbo_stream.erb +1 -0
- data/app/views/spree/waitlists/create.turbo_stream.erb +9 -0
- data/app/views/themes/default/kaminari/storefront/_first_page.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_gap.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_last_page.html.erb +8 -0
- data/app/views/themes/default/kaminari/storefront/_next_page.html.erb +13 -0
- data/app/views/themes/default/kaminari/storefront/_page.html.erb +10 -0
- data/app/views/themes/default/kaminari/storefront/_paginator.html.erb +27 -0
- data/app/views/themes/default/kaminari/storefront/_prev_page.html.erb +13 -0
- data/app/views/themes/default/spree/account/_account_nav.html.erb +46 -0
- data/app/views/themes/default/spree/account/_order.html.erb +39 -0
- data/app/views/themes/default/spree/account/_orders.html.erb +16 -0
- data/app/views/themes/default/spree/account/addresses/_address.html.erb +42 -0
- data/app/views/themes/default/spree/account/addresses/index.html.erb +28 -0
- data/app/views/themes/default/spree/account/newsletter/_newsletter_settings.html.erb +13 -0
- data/app/views/themes/default/spree/account/newsletter/edit.html.erb +16 -0
- data/app/views/themes/default/spree/account/newsletter/update.html.erb +1 -0
- data/app/views/themes/default/spree/account/orders/index.html.erb +24 -0
- data/app/views/themes/default/spree/account/orders/show.html.erb +22 -0
- data/app/views/themes/default/spree/account/profile/edit.html.erb +36 -0
- data/app/views/themes/default/spree/account/store_credits/_store_credit_event.html.erb +29 -0
- data/app/views/themes/default/spree/account/store_credits/index.html.erb +31 -0
- data/app/views/themes/default/spree/checkout/_footer.html.erb +10 -0
- data/app/views/themes/default/spree/checkout/complete.html.erb +84 -0
- data/app/views/themes/default/spree/contacts/new.html.erb +23 -0
- data/app/views/themes/default/spree/orders/_cart.html.erb +14 -0
- data/app/views/themes/default/spree/orders/_empty.html.erb +11 -0
- data/app/views/themes/default/spree/orders/_line_item.html.erb +47 -0
- data/app/views/themes/default/spree/orders/_line_item_quantity.html.erb +11 -0
- data/app/views/themes/default/spree/orders/_summary.html.erb +41 -0
- data/app/views/themes/default/spree/orders/edit.html.erb +18 -0
- data/app/views/themes/default/spree/orders/show.html.erb +6 -0
- data/app/views/themes/default/spree/page_sections/_announcement_bar.html.erb +10 -0
- data/app/views/themes/default/spree/page_sections/_custom_code.html.erb +5 -0
- data/app/views/themes/default/spree/page_sections/_featured_product.html.erb +136 -0
- data/app/views/themes/default/spree/page_sections/_featured_taxon.html.erb +116 -0
- data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +71 -0
- data/app/views/themes/default/spree/page_sections/_footer.html.erb +62 -0
- data/app/views/themes/default/spree/page_sections/_header.html.erb +166 -0
- data/app/views/themes/default/spree/page_sections/_image_banner.html.erb +57 -0
- data/app/views/themes/default/spree/page_sections/_image_with_text.html.erb +66 -0
- data/app/views/themes/default/spree/page_sections/_main_password_footer.html.erb +64 -0
- data/app/views/themes/default/spree/page_sections/_main_password_header.html.erb +54 -0
- data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +47 -0
- data/app/views/themes/default/spree/page_sections/_page_title.html.erb +7 -0
- data/app/views/themes/default/spree/page_sections/_post_details.html.erb +19 -0
- data/app/views/themes/default/spree/page_sections/_post_grid.html.erb +11 -0
- data/app/views/themes/default/spree/page_sections/_product_details.html.erb +102 -0
- data/app/views/themes/default/spree/page_sections/_product_grid.html.erb +52 -0
- data/app/views/themes/default/spree/page_sections/_related_products.html.erb +15 -0
- data/app/views/themes/default/spree/page_sections/_rich_text.html.erb +18 -0
- data/app/views/themes/default/spree/page_sections/_taxon_banner.html.erb +37 -0
- data/app/views/themes/default/spree/page_sections/_taxon_grid.html.erb +103 -0
- data/app/views/themes/default/spree/page_sections/_video.html.erb +27 -0
- data/app/views/themes/default/spree/page_sections/nav/_desktop.html.erb +49 -0
- data/app/views/themes/default/spree/page_sections/nav/_mobile.html.erb +136 -0
- data/app/views/themes/default/spree/policies/show.html.erb +11 -0
- data/app/views/themes/default/spree/posts/_json_ld.html.erb +20 -0
- data/app/views/themes/default/spree/posts/_pagination.html.erb +1 -0
- data/app/views/themes/default/spree/posts/_post.html.erb +13 -0
- data/app/views/themes/default/spree/products/_add_to_cart_button.html.erb +58 -0
- data/app/views/themes/default/spree/products/_add_to_waitlist.html.erb +36 -0
- data/app/views/themes/default/spree/products/_add_to_wishlist.html.erb +33 -0
- data/app/views/themes/default/spree/products/_breadcrumbs.html.erb +23 -0
- data/app/views/themes/default/spree/products/_color_picker.html.erb +19 -0
- data/app/views/themes/default/spree/products/_color_swatches.html.erb +61 -0
- data/app/views/themes/default/spree/products/_details.html.erb +55 -0
- data/app/views/themes/default/spree/products/_featured_image.html.erb +37 -0
- data/app/views/themes/default/spree/products/_filters.html.erb +45 -0
- data/app/views/themes/default/spree/products/_json_ld.html.erb +38 -0
- data/app/views/themes/default/spree/products/_json_ld_list.html.erb +9 -0
- data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +10 -0
- data/app/views/themes/default/spree/products/_label.html.erb +26 -0
- data/app/views/themes/default/spree/products/_media_gallery.html.erb +94 -0
- data/app/views/themes/default/spree/products/_price.html.erb +59 -0
- data/app/views/themes/default/spree/products/_product.html.erb +62 -0
- data/app/views/themes/default/spree/products/_quantity_selector.html.erb +32 -0
- data/app/views/themes/default/spree/products/_returns_policy_modal.html.erb +22 -0
- data/app/views/themes/default/spree/products/_show_more_button.html.erb +8 -0
- data/app/views/themes/default/spree/products/_sort.html.erb +45 -0
- data/app/views/themes/default/spree/products/_swiper.html.erb +85 -0
- data/app/views/themes/default/spree/products/_tags.html.erb +0 -0
- data/app/views/themes/default/spree/products/_variant_options.html.erb +71 -0
- data/app/views/themes/default/spree/products/_variant_picker.html.erb +50 -0
- data/app/views/themes/default/spree/products/filters/_availability.html.erb +32 -0
- data/app/views/themes/default/spree/products/filters/_colors.html.erb +23 -0
- data/app/views/themes/default/spree/products/filters/_generic.html.erb +75 -0
- data/app/views/themes/default/spree/products/filters/_price.html.erb +35 -0
- data/app/views/themes/default/spree/products/filters/_taxons.erb +78 -0
- data/app/views/themes/default/spree/search/_suggestions.html.erb +92 -0
- data/app/views/themes/default/spree/settings/show.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_account_pane.html.erb +28 -0
- data/app/views/themes/default/spree/shared/_address.html.erb +35 -0
- data/app/views/themes/default/spree/shared/_cart_icon.html.erb +13 -0
- data/app/views/themes/default/spree/shared/_cart_pane.html.erb +38 -0
- data/app/views/themes/default/spree/shared/_css_variables.html.erb +54 -0
- data/app/views/themes/default/spree/shared/_custom_head.html.erb +0 -0
- data/app/views/themes/default/spree/shared/_error_messages.html.erb +9 -0
- data/app/views/themes/default/spree/shared/_error_messages_without_base_attribute.html.erb +15 -0
- data/app/views/themes/default/spree/shared/_flash.html.erb +16 -0
- data/app/views/themes/default/spree/shared/_flashes.html.erb +10 -0
- data/app/views/themes/default/spree/shared/_json_ld.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_line_item_options.html.erb +18 -0
- data/app/views/themes/default/spree/shared/_logo.html.erb +42 -0
- data/app/views/themes/default/spree/shared/_meta_tags.html.erb +45 -0
- data/app/views/themes/default/spree/shared/_order_details.html.erb +106 -0
- data/app/views/themes/default/spree/shared/_order_line_item.html.erb +65 -0
- data/app/views/themes/default/spree/shared/_order_shipment.html.erb +71 -0
- data/app/views/themes/default/spree/shared/_search.html.erb +32 -0
- data/app/views/themes/default/spree/shared/_title.html.erb +3 -0
- data/app/views/themes/default/spree/shared/_wishlist_icon.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_account.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_arrow-left.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_arrow-right.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_bell.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_cart.html.erb +10 -0
- data/app/views/themes/default/spree/shared/icons/_cart_48.html.erb +6 -0
- data/app/views/themes/default/spree/shared/icons/_check.html.erb +4 -0
- data/app/views/themes/default/spree/shared/icons/_chevron.html.erb +15 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_down.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_right.html.erb +15 -0
- data/app/views/themes/default/spree/shared/icons/_chevron_up.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_close.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_cross.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_delete.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_delivery.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_disabled.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_edit.html.erb +3 -0
- data/app/views/themes/default/spree/shared/icons/_facebook.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_filter.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_heart.html.erb +12 -0
- data/app/views/themes/default/spree/shared/icons/_info.html.erb +7 -0
- data/app/views/themes/default/spree/shared/icons/_instagram.html.erb +18 -0
- data/app/views/themes/default/spree/shared/icons/_lock.html.erb +13 -0
- data/app/views/themes/default/spree/shared/icons/_menu.html.erb +10 -0
- data/app/views/themes/default/spree/shared/icons/_minus.html.erb +5 -0
- data/app/views/themes/default/spree/shared/icons/_pinch.html.erb +6 -0
- data/app/views/themes/default/spree/shared/icons/_pinterest.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_plus.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_return.html.erb +11 -0
- data/app/views/themes/default/spree/shared/icons/_search.html.erb +17 -0
- data/app/views/themes/default/spree/shared/icons/_spinner.html.erb +1 -0
- data/app/views/themes/default/spree/shared/icons/_spotify.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_tiktok.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_twitter.html.erb +16 -0
- data/app/views/themes/default/spree/shared/icons/_youtube.html.erb +9 -0
- data/app/views/themes/default/spree/shared/icons/_zoom.html.erb +10 -0
- data/app/views/themes/default/spree/wishlists/_no_wished_items.html.erb +10 -0
- data/app/views/themes/default/spree/wishlists/_wished_item.html.erb +38 -0
- data/app/views/themes/default/spree/wishlists/show.html.erb +17 -0
- data/config/i18n-tasks.yml +176 -0
- data/config/importmap.rb +22 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/heroicon.rb +10 -0
- data/config/locales/en.yml +76 -0
- data/config/routes.rb +88 -0
- data/lib/generators/spree/storefront/install/install_generator.rb +45 -0
- data/lib/generators/spree/storefront/install/templates/application.tailwind.css +1760 -0
- data/lib/generators/spree/storefront/install/templates/dev +16 -0
- data/lib/generators/spree/storefront/install/templates/tailwind.config.js +128 -0
- data/lib/generators/spree/storefront/theme/templates/model.rb.tt +12 -0
- data/lib/generators/spree/storefront/theme/theme_generator.rb +41 -0
- data/lib/spree/storefront/configuration.rb +11 -0
- data/lib/spree/storefront/engine.rb +51 -0
- data/lib/spree/storefront/testing_support/capybara_utils.rb +13 -0
- data/lib/spree/storefront.rb +16 -0
- data/lib/spree_storefront.rb +1 -0
- data/vendor/colornames.json +1 -0
- data/vendor/javascript/@kanety--stimulus-accordion.js +4 -0
- data/vendor/javascript/@stimulus-components--carousel.js +4 -0
- data/vendor/javascript/card-validator.js +4 -0
- data/vendor/javascript/credit-card-type.js +4 -0
- data/vendor/javascript/headroom.js.js +19 -0
- data/vendor/javascript/nouislider.js +4 -0
- data/vendor/javascript/photoswipe--dist--photoswipe-lightbox.esm.js.js +667 -0
- data/vendor/javascript/photoswipe.js +1675 -0
- data/vendor/javascript/stimulus-read-more.js +4 -0
- data/vendor/javascript/stimulus-scroll-to.js +4 -0
- data/vendor/javascript/swiper--bundle.js +4 -0
- metadata +567 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
module Spree
|
2
|
+
class StoreController < BaseController
|
3
|
+
include Spree::Core::ControllerHelpers::Order
|
4
|
+
|
5
|
+
include Spree::LocaleUrls
|
6
|
+
include Spree::ThemeConcern
|
7
|
+
include Spree::StorefrontHelper
|
8
|
+
include Spree::PasswordProtected
|
9
|
+
include Spree::WishlistHelper
|
10
|
+
include Spree::AnalyticsHelper
|
11
|
+
|
12
|
+
layout :choose_layout
|
13
|
+
|
14
|
+
helper 'spree/base'
|
15
|
+
helper 'spree/locale'
|
16
|
+
helper 'spree/storefront_locale'
|
17
|
+
helper 'spree/currency'
|
18
|
+
helper 'spree/addresses'
|
19
|
+
helper 'spree/wishlist'
|
20
|
+
|
21
|
+
helper_method :title
|
22
|
+
helper_method :title=
|
23
|
+
helper_method :accurate_title
|
24
|
+
|
25
|
+
helper_method :current_taxon, :store_filter_names
|
26
|
+
|
27
|
+
helper_method :permitted_products_params, :products_filters_params,
|
28
|
+
:storefront_products_scope, :storefront_products,
|
29
|
+
:default_products_sort, :default_products_finder_params
|
30
|
+
|
31
|
+
before_action :redirect_to_default_locale
|
32
|
+
before_action :render_404_if_store_not_exists
|
33
|
+
rescue_from ActionController::InvalidAuthenticityToken, with: :invalid_authenticity_token
|
34
|
+
|
35
|
+
def render_404_if_store_not_exists
|
36
|
+
return if current_store.present?
|
37
|
+
|
38
|
+
render 'errors/404', layout: 'application', status: :not_found
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_taxon
|
42
|
+
@current_taxon ||= (current_store.taxons.find_by(id: params[:taxon_id]) if params[:taxon_id].present?)
|
43
|
+
end
|
44
|
+
|
45
|
+
def store_filter_names
|
46
|
+
@store_filter_names ||= Spree::OptionType.filterable.order(:position).pluck(:name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def store_filter_names_hash
|
50
|
+
filter_names = {}
|
51
|
+
store_filter_names.each do |filter_name|
|
52
|
+
filter_names[filter_name.to_sym] = []
|
53
|
+
end
|
54
|
+
filter_names
|
55
|
+
end
|
56
|
+
|
57
|
+
def permitted_products_params
|
58
|
+
@permitted_products_params ||= params.permit(
|
59
|
+
:locale,
|
60
|
+
:currency,
|
61
|
+
:q,
|
62
|
+
:page,
|
63
|
+
:per_page,
|
64
|
+
:sort_by,
|
65
|
+
filter: [
|
66
|
+
:min_price,
|
67
|
+
:max_price,
|
68
|
+
:purchasable,
|
69
|
+
:out_of_stock,
|
70
|
+
{
|
71
|
+
options: [store_filter_names_hash],
|
72
|
+
taxon_ids: []
|
73
|
+
}
|
74
|
+
]
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_products_sort
|
79
|
+
'manual'
|
80
|
+
end
|
81
|
+
|
82
|
+
def products_filters_params
|
83
|
+
@products_filters_params ||= permitted_products_params[:filter]&.compact_blank || {}
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def choose_layout
|
89
|
+
if turbo_frame_request? && !current_theme_preview.present?
|
90
|
+
'turbo_rails/frame'
|
91
|
+
else
|
92
|
+
'spree/storefront'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# can be used in views as well as controllers.
|
97
|
+
# e.g. <% self.title = 'This is a custom title for this view' %>
|
98
|
+
attr_writer :title
|
99
|
+
|
100
|
+
def title
|
101
|
+
title_string = @title.present? ? @title : accurate_title
|
102
|
+
if title_string.present?
|
103
|
+
title_string
|
104
|
+
else
|
105
|
+
default_title
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def default_title
|
110
|
+
@default_title ||= current_store.name
|
111
|
+
end
|
112
|
+
|
113
|
+
# this is a hook for subclasses to provide title
|
114
|
+
def accurate_title
|
115
|
+
@accurate_title ||= current_store.seo_title.presence || current_store.name
|
116
|
+
end
|
117
|
+
|
118
|
+
def storefront_products_scope
|
119
|
+
current_store.products.active(current_currency)
|
120
|
+
end
|
121
|
+
|
122
|
+
def default_products_finder_params
|
123
|
+
taxon = @taxon || current_taxon
|
124
|
+
|
125
|
+
filter = permitted_products_params.fetch(:filter, {}).dup
|
126
|
+
|
127
|
+
filter[:taxon_ids] ||= [taxon&.id.to_s].compact
|
128
|
+
filter[:taxons] = filter[:taxon_ids].join(',')
|
129
|
+
|
130
|
+
if filter.key?(:min_price) || filter.key?(:max_price)
|
131
|
+
min_price = filter[:min_price].presence || 0
|
132
|
+
max_price = filter[:max_price].presence || 'Infinity'
|
133
|
+
|
134
|
+
filter[:price] = [min_price, max_price].compact.join(',')
|
135
|
+
end
|
136
|
+
|
137
|
+
permitted_products_params.merge(
|
138
|
+
store: current_store,
|
139
|
+
filter: filter,
|
140
|
+
currency: current_currency
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
def storefront_products
|
145
|
+
@storefront_products ||= begin
|
146
|
+
finder_params = default_products_finder_params
|
147
|
+
finder_params[:sort_by] ||= @taxon&.sort_order || 'manual'
|
148
|
+
|
149
|
+
products_finder = Spree::Dependencies.products_finder.constantize
|
150
|
+
products = products_finder.
|
151
|
+
new(scope: storefront_products_scope, params: finder_params).
|
152
|
+
execute.
|
153
|
+
includes(storefront_products_includes)
|
154
|
+
|
155
|
+
default_per_page = Spree::Storefront::Config[:products_per_page]
|
156
|
+
per_page = params[:per_page].present? ? params[:per_page].to_i : default_per_page
|
157
|
+
page = params[:page].present? ? params[:page].to_i : 1
|
158
|
+
|
159
|
+
products.page(page).per(per_page)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def storefront_products_includes
|
164
|
+
[
|
165
|
+
:prices_including_master,
|
166
|
+
:variant_images,
|
167
|
+
:option_types,
|
168
|
+
:option_values,
|
169
|
+
{ master: [:images, :prices, :stock_items, :stock_locations, { stock_items: :stock_location }],
|
170
|
+
variants: [
|
171
|
+
:images, :prices, :option_values, :stock_items, :stock_locations,
|
172
|
+
{ option_values: :option_type, stock_items: :stock_location }
|
173
|
+
],
|
174
|
+
taxons: [:taxonomy],
|
175
|
+
taggings: [:tag] }
|
176
|
+
]
|
177
|
+
end
|
178
|
+
|
179
|
+
def redirect_unauthorized_access
|
180
|
+
if try_spree_current_user
|
181
|
+
flash[:error] = Spree.t(:authorization_failure)
|
182
|
+
redirect_to spree.forbidden_path
|
183
|
+
else
|
184
|
+
store_location
|
185
|
+
if respond_to?(:spree_login_path)
|
186
|
+
redirect_to spree_login_path
|
187
|
+
else
|
188
|
+
redirect_to spree.root_path
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def redirect_back_or_default(default)
|
194
|
+
redirect_to(session[:user_return_to] || default)
|
195
|
+
end
|
196
|
+
|
197
|
+
def require_user(return_to = nil)
|
198
|
+
return if try_spree_current_user
|
199
|
+
|
200
|
+
store_location(return_to)
|
201
|
+
|
202
|
+
respond_to do |format|
|
203
|
+
format.html { redirect_to spree_login_path }
|
204
|
+
format.turbo_stream { render turbo_stream: turbo_stream.slideover_open('slideover-account', 'account-pane') }
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# this will work for devise out of the box
|
209
|
+
# for other auth systems you will need to override this method
|
210
|
+
def store_location(location = nil)
|
211
|
+
return if try_spree_current_user
|
212
|
+
return unless defined?(store_location_for)
|
213
|
+
return unless defined?(Devise)
|
214
|
+
|
215
|
+
location ||= request.fullpath
|
216
|
+
|
217
|
+
store_location_for(Devise.mappings.keys.first, location)
|
218
|
+
end
|
219
|
+
|
220
|
+
def redirect_to_cart
|
221
|
+
redirect_to spree.cart_path
|
222
|
+
end
|
223
|
+
|
224
|
+
def clear_order_token
|
225
|
+
cookies.delete(:token)
|
226
|
+
end
|
227
|
+
|
228
|
+
def disable_sesion_tracking
|
229
|
+
request.session_options[:skip] = true
|
230
|
+
end
|
231
|
+
|
232
|
+
def invalid_authenticity_token(exception)
|
233
|
+
Rails.error.report(
|
234
|
+
exception,
|
235
|
+
context: { user_id: spree_current_user&.id },
|
236
|
+
source: 'spree.storefront'
|
237
|
+
)
|
238
|
+
|
239
|
+
flash[:error] = Spree.t(:something_went_wrong)
|
240
|
+
|
241
|
+
respond_to do |format|
|
242
|
+
format.html { redirect_back_or_to root_path }
|
243
|
+
format.turbo_stream { render turbo_stream: turbo_stream.update('flash', partial: 'spree/shared/flashes') }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Spree
|
2
|
+
class TaxonomiesController < Spree::StoreController
|
3
|
+
def show
|
4
|
+
@taxonomy = current_store.taxons.where(parent_id: nil).friendly.find(params[:id])
|
5
|
+
|
6
|
+
@taxons = @taxonomy.children.order(name: :asc)
|
7
|
+
taxons_grouped = @taxons.group_by { |b| b.name[0].upcase }
|
8
|
+
|
9
|
+
numbers = ('0'..'9').to_a
|
10
|
+
alphabet_letters = ('A'..'Z').to_a
|
11
|
+
|
12
|
+
@taxons_grouped_by_letter = begin
|
13
|
+
taxons_grouped_by_letter = {}
|
14
|
+
alphabet_letters.each do |letter|
|
15
|
+
taxons_grouped_by_letter[letter] = taxons_grouped[letter]
|
16
|
+
end
|
17
|
+
taxons_grouped_by_letter
|
18
|
+
end
|
19
|
+
|
20
|
+
@taxons_grouped_by_numbers = taxons_grouped.select { |k, _v| numbers.include?(k) }
|
21
|
+
@taxons_grouped_by_other = taxons_grouped.select { |k, _v| alphabet_letters.concat(numbers).exclude?(k) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def accurate_title
|
27
|
+
@taxonomy.root.seo_title.presence || @taxonomy.root.name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Spree
|
2
|
+
class TaxonsController < Spree::StoreController
|
3
|
+
include Spree::StorefrontHelper
|
4
|
+
helper 'spree/products'
|
5
|
+
|
6
|
+
before_action :load_taxon
|
7
|
+
after_action :track_show, only: :show
|
8
|
+
|
9
|
+
def show
|
10
|
+
redirect_if_legacy_path unless turbo_frame_request? || turbo_stream_request?
|
11
|
+
|
12
|
+
@current_page = current_theme.pages.find_by(type: 'Spree::Pages::Taxon')
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def accurate_title
|
18
|
+
load_taxon unless @taxon
|
19
|
+
@taxon.seo_title
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_taxon
|
23
|
+
@taxon ||= find_with_fallback_default_locale { current_store.taxons.friendly.find(params[:id]) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def track_show
|
27
|
+
return if turbo_frame_request? || turbo_stream_request?
|
28
|
+
|
29
|
+
track_event('product_list_viewed', { taxon: @taxon })
|
30
|
+
end
|
31
|
+
|
32
|
+
def redirect_if_legacy_path
|
33
|
+
# If an old id or a numeric id was used to find the record,
|
34
|
+
# we should do a 301 redirect that uses the current friendly id.
|
35
|
+
if params[:id] != @taxon.friendly_id
|
36
|
+
params[:id] = @taxon.friendly_id
|
37
|
+
params.permit!
|
38
|
+
redirect_to url_for(params), status: :moved_permanently
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_products_sort
|
43
|
+
@taxon.sort_order
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Spree
|
2
|
+
class WishlistsController < StoreController
|
3
|
+
def show
|
4
|
+
if params[:id].present? && params[:token].present?
|
5
|
+
@wishlist = current_store.wishlists.find_by!(id: params[:id], token: params[:token])
|
6
|
+
elsif try_spree_current_user
|
7
|
+
# https://github.com/spree/spree/blob/9475c6633b762669ee0c8f1f8a4d73e1c221a94e/core/app/models/concerns/spree/user_methods.rb#L71
|
8
|
+
@wishlist = try_spree_current_user.default_wishlist_for_store(current_store)
|
9
|
+
else
|
10
|
+
return require_user
|
11
|
+
end
|
12
|
+
|
13
|
+
@wished_items = @wishlist.wished_items.includes(
|
14
|
+
product: [:prices_including_master, :variants, :master, :taggings],
|
15
|
+
variant: [:images, :product, { option_values: :option_type }]
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Spree
|
2
|
+
module Storefront
|
3
|
+
class VariantFinder
|
4
|
+
def initialize(product:, current_currency:, variant_id: nil, options_hash: {})
|
5
|
+
@product = product
|
6
|
+
@variant_id = variant_id
|
7
|
+
@current_currency = current_currency
|
8
|
+
@options_hash = options_hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def find
|
12
|
+
try_variant_from_options
|
13
|
+
return [@selected_variant, @variant_from_options] if @selected_variant.present?
|
14
|
+
|
15
|
+
try_any_variant
|
16
|
+
[@selected_variant, @variant_from_options]
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :current_currency, :options_hash, :variant_id
|
22
|
+
|
23
|
+
def try_variant_from_options
|
24
|
+
return unless options_hash.present?
|
25
|
+
return unless (@product.option_type_ids.map(&:to_s) - options_hash.keys).empty?
|
26
|
+
|
27
|
+
@product.variants.each do |variant|
|
28
|
+
options_matched = options_hash.all? do |option_type_id, name|
|
29
|
+
variant.option_values.any? { |ov| ov.option_type_id.to_s == option_type_id && ov.name.downcase.strip == name.downcase.strip }
|
30
|
+
end
|
31
|
+
|
32
|
+
if options_matched && variant.purchasable? && variant.price_in(current_currency).amount.present?
|
33
|
+
@selected_variant = variant
|
34
|
+
@variant_from_options = variant
|
35
|
+
break
|
36
|
+
elsif options_matched
|
37
|
+
@variant_from_options = variant
|
38
|
+
break
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def try_any_variant
|
44
|
+
if @product.has_variants?
|
45
|
+
if options_hash.present? # if selected combination is not purchasable nor active
|
46
|
+
@selected_variant = nil
|
47
|
+
elsif variant_id.present?
|
48
|
+
variant = @product.variants.find(variant_id)
|
49
|
+
@variant_from_options = variant
|
50
|
+
@selected_variant = variant
|
51
|
+
elsif product_option_types.size == 1 && product_option_types.first.color?
|
52
|
+
@selected_variant = @variant_from_options = @product.variants.find { |v| v.purchasable? && v.price_in(current_currency).amount.present? }
|
53
|
+
elsif @product.variants.size == 1 || product_has_only_one_secondary_option_type_value?
|
54
|
+
@variant_from_options = @product.variants.first
|
55
|
+
@selected_variant = @variant_from_options
|
56
|
+
end
|
57
|
+
elsif @product.master.purchasable? && @product.master.price_in(current_currency).amount.present?
|
58
|
+
@selected_variant = @variant_from_options = @product.master
|
59
|
+
else
|
60
|
+
@selected_variant = nil
|
61
|
+
@variant_from_options = @product.master
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def product_has_only_one_secondary_option_type_value?
|
66
|
+
return false unless product_option_types.size == 2
|
67
|
+
return false unless product_option_types.first.color?
|
68
|
+
|
69
|
+
@product.
|
70
|
+
option_values.
|
71
|
+
select { |ov| ov.option_type_id == product_option_types.last.id }.
|
72
|
+
uniq(&:id).size == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def product_option_types
|
76
|
+
@product_option_types ||= @product.option_types.to_a
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Spree
|
2
|
+
module AnalyticsHelper
|
3
|
+
def analytics_event_handlers
|
4
|
+
@analytics_event_handlers ||= Spree::Analytics.event_handlers.map do |handler|
|
5
|
+
handler.new(user: try_spree_current_user, session: session, request: request)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def track_event(event_name, record)
|
10
|
+
return if current_theme_preview.present?
|
11
|
+
return if unsupported_event?(event_name)
|
12
|
+
|
13
|
+
analytics_event_handlers.each do |handler|
|
14
|
+
handler.handle_event(event_name, record)
|
15
|
+
end
|
16
|
+
rescue => e
|
17
|
+
Rails.error.report(
|
18
|
+
e,
|
19
|
+
context: { event_name: event_name, record_id: record&.id, record_type: record&.class&.name },
|
20
|
+
source: 'spree.storefront'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsupported_event?(event_name)
|
25
|
+
!Spree::Analytics.events.key?(event_name.to_sym)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Spree
|
2
|
+
module CartHelper
|
3
|
+
def quantity_field_options(opts = {})
|
4
|
+
opts[:min] ||= 1
|
5
|
+
opts[:max] ||= maximum_quantity
|
6
|
+
|
7
|
+
{
|
8
|
+
min: opts[:min], max: opts[:max],
|
9
|
+
class: opts[:class],
|
10
|
+
data: { 'quantity-picker-target': 'quantity' },
|
11
|
+
aria: { label: Spree.t(:quantity) }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def quantity_modifier_button_tag(text = '+', opts = {})
|
16
|
+
opts[:action] ||= 'increase'
|
17
|
+
opts[:type] ||= 'button'
|
18
|
+
|
19
|
+
button_tag(
|
20
|
+
text,
|
21
|
+
type: opts[:type],
|
22
|
+
class: opts[:class],
|
23
|
+
data: {
|
24
|
+
'quantity-picker-target': opts[:action],
|
25
|
+
action: "click->quantity-picker##{opts[:action]} click->cart#disableCart"
|
26
|
+
}
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def color_options_style_for_line_items(line_items)
|
31
|
+
@color_options_style_for_line_items = begin
|
32
|
+
colors = line_items.map(&:variant).map do |v|
|
33
|
+
color_option_values = v.option_values.find_all do |ov|
|
34
|
+
ov.option_type.color?
|
35
|
+
end
|
36
|
+
|
37
|
+
color_option_values.map do |ov|
|
38
|
+
{ name: ov.name, filter_name: ov.name }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
colors = colors.flatten.uniq { |color| [color[:name], color[:filter_name]] }
|
43
|
+
|
44
|
+
Spree::ColorsPreviewStylesPresenter.new(colors).to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Spree
|
2
|
+
module CheckoutAnalyticsHelper
|
3
|
+
def coupon_tracking_params
|
4
|
+
{
|
5
|
+
order: @order,
|
6
|
+
coupon_code: params[:coupon_code],
|
7
|
+
coupon_handler: @result
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def clean_analytics_session
|
12
|
+
session.delete(:checkout_started)
|
13
|
+
session.delete(:checkout_step_viewed)
|
14
|
+
session.delete(:checkout_step_completed)
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear_checkout_completed_session
|
18
|
+
session.delete(:checkout_completed)
|
19
|
+
end
|
20
|
+
|
21
|
+
def order_tracking_params
|
22
|
+
tracking_params = {
|
23
|
+
last_ip_address: request.remote_ip,
|
24
|
+
}
|
25
|
+
|
26
|
+
tracking_params[:ahoy_visit_id] = current_visit.id if @order.respond_to?(:ahoy_visit) && defined?(current_visit) && current_visit&.id
|
27
|
+
tracking_params
|
28
|
+
end
|
29
|
+
|
30
|
+
def track_checkout_started
|
31
|
+
# server-side tracking
|
32
|
+
track_event('checkout_started', { order: @order })
|
33
|
+
|
34
|
+
# client-side tracking
|
35
|
+
session[:checkout_started] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def track_checkout_entered_email
|
39
|
+
return unless @order.email.present?
|
40
|
+
return unless params.dig(:order, :email).present?
|
41
|
+
|
42
|
+
track_event('checkout_email_entered', { order: @order, email: @order.email })
|
43
|
+
end
|
44
|
+
|
45
|
+
def track_payment_info_entered
|
46
|
+
return unless @order.payment_method.present?
|
47
|
+
return unless params.dig(:order, :payments_attributes).present?
|
48
|
+
|
49
|
+
track_event('payment_info_entered', { order: @order })
|
50
|
+
end
|
51
|
+
|
52
|
+
def track_checkout_step_viewed
|
53
|
+
# server-side tracking
|
54
|
+
track_event('checkout_step_viewed', { order: @order, step: params[:state] || @order.state })
|
55
|
+
|
56
|
+
# client-side tracking
|
57
|
+
trackable_checkout_steps = @order.checkout_steps[0..2]
|
58
|
+
session[:checkout_step_viewed] = true if trackable_checkout_steps.include? @order.state
|
59
|
+
end
|
60
|
+
|
61
|
+
def track_checkout_step_completed
|
62
|
+
# server-side tracking
|
63
|
+
track_event('checkout_step_completed', { order: @order, step: @previous_state })
|
64
|
+
|
65
|
+
# client-side tracking
|
66
|
+
session[:checkout_step_completed] = @previous_state # for 3rd party frontend tracking
|
67
|
+
end
|
68
|
+
|
69
|
+
def track_checkout_completed
|
70
|
+
# server-side tracking
|
71
|
+
track_event('checkout_completed', { order: @order })
|
72
|
+
|
73
|
+
# client-side tracking
|
74
|
+
session[:checkout_completed] = true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Spree
|
2
|
+
module CheckoutHelper
|
3
|
+
def checkout_progress(numbers: false)
|
4
|
+
states = (@order.checkout_steps - ['complete']).unshift('cart')
|
5
|
+
states -= ['delivery'] if @order.digital?
|
6
|
+
|
7
|
+
items = states.each_with_index.map do |state, i|
|
8
|
+
text = Spree.t("order_state.#{state}").titleize
|
9
|
+
text.prepend("#{i.succ}. ") if numbers
|
10
|
+
|
11
|
+
css_classes = ['breadcrumb-item']
|
12
|
+
|
13
|
+
if @order.passed_checkout_step?(state)
|
14
|
+
link_content = text
|
15
|
+
link_url = if state == 'cart'
|
16
|
+
spree.cart_url(host: current_store.url_or_custom_domain, order_token: @order.token)
|
17
|
+
else
|
18
|
+
spree.checkout_state_path(@order.token, state)
|
19
|
+
end
|
20
|
+
|
21
|
+
text = link_to(link_content, link_url)
|
22
|
+
css_classes << 'text-primary'
|
23
|
+
content_tag('li', text, class: css_classes.join(' '))
|
24
|
+
else
|
25
|
+
content_tag('li', text, class: "breadcrumb-item #{state == @order.state ? 'font-bold' : 'text-text'}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
content_tag('ol', raw(items.join("\n")), class: 'breadcrumb flex items-center py-6 gap-2', id: "checkout-step-#{@order.state}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def checkout_available_payment_methods
|
32
|
+
@checkout_available_payment_methods ||= @order.available_payment_methods.reject(&:store_credit?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def checkout_started?
|
36
|
+
@order.state == 'address' && @order.state_was == 'cart'
|
37
|
+
end
|
38
|
+
|
39
|
+
def already_have_an_account?
|
40
|
+
@already_have_an_account ||= @order.email.present? && Spree.user_class.exists?(email: @order.email.downcase)
|
41
|
+
end
|
42
|
+
|
43
|
+
def checkout_payment_sources(payment_method = nil)
|
44
|
+
return [] unless try_spree_current_user.respond_to?(:payment_sources)
|
45
|
+
|
46
|
+
payment_method.present? ? try_spree_current_user.payment_sources.where(payment_method: payment_method) : try_spree_current_user.payment_sources
|
47
|
+
end
|
48
|
+
|
49
|
+
def quick_checkout_enabled?(order)
|
50
|
+
order.payment_required? && order.shipments.count <= 1 &&
|
51
|
+
(order.digital? || !order.some_digital?) # Either fully digital or not digital at all
|
52
|
+
end
|
53
|
+
|
54
|
+
def can_use_store_credit_on_checkout?(order)
|
55
|
+
order.could_use_store_credit? && (!order.respond_to?(:gift_card) || !order.gift_card.present?)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|