diff --git a/.codeclimate.yml b/.codeclimate.yml index 3880986cad..1892bc1fb8 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -16,6 +16,10 @@ plugins: enabled: false PropertySortOrder: enabled: false + StringQuotes: + enabled: false + DeclarationOrder: + enabled: false duplication: enabled: true exclude_patterns: diff --git a/app/assets/images/menu/btn-menu-mobile.png b/app/assets/images/menu/btn-menu-mobile.png new file mode 100644 index 0000000000..1d2d414473 Binary files /dev/null and b/app/assets/images/menu/btn-menu-mobile.png differ diff --git a/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee index ebad820ebd..28d6cb4cfe 100644 --- a/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee @@ -1,2 +1,4 @@ -Darkswarm.controller "CartCtrl", ($scope, Cart, $timeout) -> +Darkswarm.controller "CartCtrl", ($scope, Cart, CurrentHub) -> $scope.Cart = Cart + $scope.CurrentHub = CurrentHub + $scope.max_characters = 20 diff --git a/app/assets/javascripts/darkswarm/controllers/cart_dropdown_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/cart_dropdown_controller.js.coffee new file mode 100644 index 0000000000..048459ecd8 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/cart_dropdown_controller.js.coffee @@ -0,0 +1,7 @@ +Darkswarm.controller "CartDropdownCtrl", ($scope, Cart, BodyScroll) -> + $scope.Cart = Cart + $scope.showCartSidebar = false + + $scope.toggleCartSidebar = -> + $scope.showCartSidebar = !$scope.showCartSidebar + BodyScroll.toggle() diff --git a/app/assets/javascripts/darkswarm/directives/body_scroll.js.coffee b/app/assets/javascripts/darkswarm/directives/body_scroll.js.coffee new file mode 100644 index 0000000000..183d828d03 --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/body_scroll.js.coffee @@ -0,0 +1,9 @@ +Darkswarm.directive "bodyScroll", ($rootScope, BodyScroll) -> + restrict: 'A' + scope: true + link: (scope, elem, attrs) -> + $rootScope.$on "toggleBodyScroll", -> + if BodyScroll.disabled + elem.addClass "disable-scroll" + else + elem.removeClass "disable-scroll" diff --git a/app/assets/javascripts/darkswarm/directives/cart_toggle.js.coffee b/app/assets/javascripts/darkswarm/directives/cart_toggle.js.coffee deleted file mode 100644 index cb7e574d87..0000000000 --- a/app/assets/javascripts/darkswarm/directives/cart_toggle.js.coffee +++ /dev/null @@ -1,19 +0,0 @@ -Darkswarm.directive "cartToggle", ($document) -> - # Toggles visibility of the "cart" popover - restrict: 'A' - link: (scope, elem, attr)-> - scope.open = false - - $document.bind 'click', (event) -> - cart_button = elem[0] - element_and_parents = [event.target, event.target.parentElement, event.target.parentElement.parentElement] - cart_button_clicked = (element_and_parents.indexOf(cart_button) != -1) - - if cart_button_clicked - scope.$apply -> - scope.open = !scope.open - else - scope.$apply -> - scope.open = false - - return diff --git a/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee b/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee index a3858444ae..666daaec64 100644 --- a/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/page_alert.js.coffee @@ -14,8 +14,8 @@ Darkswarm.directive "ofnPageAlert", ($timeout) -> # Wait a moment after page load before showing the alert. Otherwise we often miss the # start of the animation. $timeout -> - container_elems.addClass("move-down") + container_elems.addClass("move-up") , 1000 scope.close = -> - container_elems.removeClass("move-down") + container_elems.removeClass("move-up") diff --git a/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee b/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee index c3bcc9590d..34552016c4 100644 --- a/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee @@ -10,6 +10,5 @@ Darkswarm.directive "ofnSmoothScrollTo", ($location, $document)-> # Scrolling is confused by our position:fixed top bar and page alert bar # - add an offset to scroll to the correct location, plus 5px buffer offset = $("nav.top-bar").height() - offset += $(".page-alert.move-down").height() offset += 5 $document.scrollTo target, offset, 1000 diff --git a/app/assets/javascripts/darkswarm/services/body_scroll.js.coffee b/app/assets/javascripts/darkswarm/services/body_scroll.js.coffee new file mode 100644 index 0000000000..84c8ed9337 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/body_scroll.js.coffee @@ -0,0 +1,7 @@ +angular.module("Darkswarm").factory "BodyScroll", ($rootScope) -> + new class BodyScroll + disabled: false + + toggle: -> + @disabled = !@disabled + $rootScope.$broadcast "toggleBodyScroll" diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee index 456fd00f01..a650db5cd7 100644 --- a/app/assets/javascripts/darkswarm/services/variants.js.coffee +++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee @@ -20,7 +20,6 @@ Darkswarm.factory 'Variants', -> name = variant.product_name else name = "#{variant.product_name} - #{variant.name_to_display}" - name += " (#{variant.options_text})" if variant.options_text name lineItemFor: (variant) -> diff --git a/app/assets/stylesheets/darkswarm/cart-dropdown.css.scss b/app/assets/stylesheets/darkswarm/cart-dropdown.css.scss new file mode 100644 index 0000000000..ca3dd6a1a2 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/cart-dropdown.css.scss @@ -0,0 +1,124 @@ +@import "mixins"; +@import "variables"; +@import "branding"; + +.expanding-sidebar.cart-sidebar { + .background { + z-index: 150; + } + + .sidebar { + padding: $topbar-height 0 0; + background-color: $white; + z-index: 160; + + @include breakpoint(desktop) { + padding: $mobile-nav-height 0 0; + } + } + + .cart-header { + background-color: $white; + border-bottom: 1px solid $grey-100; + min-height: 3.5em; + padding: 1em; + position: sticky; + top: 0; + + .title { + color: $grey-800; + margin: 0; + } + + .close { + color: $grey-500; + float: right; + + i { + vertical-align: middle; + } + } + } + + .cart-content { + margin-bottom: $sidebar-footer-height + 2em; + + .cart-empty { + text-align: center; + padding-top: 10em; + width: 100%; + + p { + font-size: 1.5em; + } + } + } + + .go-shopping { + display: none; + padding: 0 1.5em; + + @include breakpoint(mobile) { + display: inline-block; + } + } + + table { + width: 100%; + border: 0; + border-spacing: 0; + margin: 0; + + .product-cart { + background-color: $white; + + td { + border-bottom: 1px solid $grey-100; + padding: 0.75em 1em 0.5em; + vertical-align: top; + + &.image { + width: 42px; + padding: 0.5em 0 0.5em 1em; + } + + span { + color: $grey-800; + font-size: 16px; + line-height: 1.4em; + } + + img { + max-width: 56px; + max-height: 56px; + } + + .options-text { + color: $grey-500; + font-size: 14px; + } + } + } + } + + .cart-total { + color: $white; + text-align: center; + margin: -0.5em 0 0.75em; + } + + .sidebar, + .sidebar-footer { + width: 375px; + margin-right: -375px; + + @include breakpoint(mobile) { + width: 100%; + margin-right: -100%; + } + } + + .sidebar-footer { + z-index: 170; + } +} diff --git a/app/assets/stylesheets/darkswarm/cart-page.css.scss b/app/assets/stylesheets/darkswarm/cart-page.css.scss new file mode 100644 index 0000000000..b2b17fa0bb --- /dev/null +++ b/app/assets/stylesheets/darkswarm/cart-page.css.scss @@ -0,0 +1,75 @@ +@import "mixins"; +@import "branding"; +@import "compass/css3/user-interface"; +@import "variables"; + +#update-cart { + #errorExplanation { + display: none; + } +} + +#cart-detail { + .cart-item-delete, + .bought-item-delete { + a { + font-size: 1.125em; + } + } + + .out-of-stock { + color: $clr-brick; + } + + button, + .button { + margin: 0; + } + + .toggle-bought { + cursor: pointer; + } + + .bought td { + color: $med-grey; + + h5 { + color: $med-grey; + } + + .already-confirmed { + float: right; + } + } + + input { + &.ng-invalid-stock, + &.ng-invalid-number { + border: 1px solid $clr-brick; + } + } +} + +.item-thumb-image { + display: none; + + @media screen and (min-width: 640px) { + display: inline-block; + float: left; + padding-right: 0.5em; + width: 36px; + height: 36px; + } +} + +.links { + .button { + padding: 1.125rem 0 1.1875rem; + width: 210px; + font-size: 1.1em; + + @include breakpoint(mobile) { + width: 100%; + } + } +} diff --git a/app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss b/app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss new file mode 100644 index 0000000000..da1034cf42 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss @@ -0,0 +1,79 @@ +@import "mixins"; +@import "variables"; +@import "branding"; + +.expanding-sidebar { + display: flex; + flex-direction: column; + height: 100%; + + .background { + position: fixed; + top: 0; + right: 0; + z-index: 200; + height: 100%; + width: 100%; + background-color: $shop-sidebar-overlay; + opacity: 0; + transition: opacity $transition-sidebar; + } + + &.shown { + .background { + opacity: 1; + } + + .sidebar, + .sidebar-footer { + margin-right: 0; + } + } + + .sidebar { + position: fixed; + top: 0; + right: 0; + z-index: 210; + height: 100%; + width: $sidebar-large-width; + margin-right: -$sidebar-large-width; + background-color: rgba($white, 0.95); + padding: 1em; + transition: margin $transition-sidebar; + overflow-y: auto; + } + + .sidebar-footer { + background-color: $grey-800; + width: $sidebar-large-width; + margin-right: -$sidebar-large-width; + min-height: $sidebar-footer-height; + position: fixed; + bottom: 0; + right: 0; + transition: margin $transition-sidebar; + padding: 1em; + + button, + a.button { + width: 48%; + } + } + + @include breakpoint(tablet) { + .sidebar, + .sidebar-footer { + width: $sidebar-medium-width; + margin-right: -$sidebar-medium-width; + } + } + + @include breakpoint(mobile) { + .sidebar, + .sidebar-footer { + width: $sidebar-small-width; + margin-right: -$sidebar-small-width; + } + } +} diff --git a/app/assets/stylesheets/darkswarm/menu.css.scss b/app/assets/stylesheets/darkswarm/menu.css.scss index abefec7a23..774d2bc146 100644 --- a/app/assets/stylesheets/darkswarm/menu.css.scss +++ b/app/assets/stylesheets/darkswarm/menu.css.scss @@ -11,6 +11,7 @@ nav.top-bar { font-size: 16px; margin-bottom: 0; height: $topbar-height; + z-index: 190; } @media #{$large-only} { @@ -174,7 +175,7 @@ nav.top-bar { height: $mobile-nav-height; position: fixed; width: 100%; - z-index: 1; + z-index: 190; // Above cart sidebar and shaded overlay .cart-span { background-color: #f4704c; @@ -225,14 +226,7 @@ nav.top-bar { .off-canvas-wrap .tab-bar .menu-icon { @include box-shadow(none); -} - -.off-canvas-wrap.move-right .tab-bar .menu-icon span { - box-shadow: 0 0px 0 1px #666, 0 7px 0 1px #666, 0 14px 0 1px #666; -} - -.tab-bar .menu-icon span::after { - box-shadow: 0 0 0 1px black, 0 7px 0 1px black, 0 14px 0 1px black; + text-indent: 0; } .tab-bar .ofn-logo { diff --git a/app/assets/stylesheets/darkswarm/page_alert.css.scss b/app/assets/stylesheets/darkswarm/page_alert.css.scss index a9276ab56d..08f35944c9 100644 --- a/app/assets/stylesheets/darkswarm/page_alert.css.scss +++ b/app/assets/stylesheets/darkswarm/page_alert.css.scss @@ -55,19 +55,18 @@ $page-alert-height: 55px; .off-canvas-fixed nav.tab-bar, .off-canvas-fixed .page-alert { @include transition(all 1000ms ease-in-out); - - &.move-down { - margin-top: $page-alert-height; - } } .off-canvas-wrap .page-alert { - top: -1 * $page-alert-height; + bottom: -1 * $page-alert-height; + top: unset; z-index: 100; -} -.off-canvas-wrap.move-right .inner-wrap.move-down { - .left-off-canvas-menu { - top: -1 * $page-alert-height; + &.move-up { + bottom: 0; + } + + .alert-box { + border-bottom: 0; } } diff --git a/app/assets/stylesheets/darkswarm/shop.css.scss b/app/assets/stylesheets/darkswarm/shop.css.scss index 0c46523184..6f411db6e9 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.scss +++ b/app/assets/stylesheets/darkswarm/shop.css.scss @@ -11,88 +11,7 @@ @import "shop-taxon-flag"; @import "shop-popovers"; -$sidebar-small-width: 75%; -$sidebar-medium-width: 65%; -$sidebar-large-width: 45%; -$sidebar-footer-height: 5em; - .darkswarm { - .shop-filters-sidebar { - display: flex; - flex-direction: column; - height: 100%; - - .background { - position: fixed; - top: 0; - right: 0; - z-index: 200; - height: 100%; - width: 100%; - background-color: $shop-sidebar-overlay; - opacity: 0; - transition: opacity $transition-sidebar; - } - - &.shown { - .background { - opacity: 1; - } - - .sidebar, .sidebar-footer { - margin-right: 0; - } - } - - .sidebar { - position: fixed; - top: 0; - right: 0; - z-index: 210; - height: 100%; - width: $sidebar-large-width; - margin-right: -$sidebar-large-width; - background-color: rgba($white, 0.95); - padding: 1em; - transition: margin $transition-sidebar; - overflow-y: scroll; - - .property-selectors { - margin-bottom: $sidebar-footer-height + 2em; - } - } - - .sidebar-footer { - background-color: $grey-800; - width: $sidebar-large-width; - margin-right: -$sidebar-large-width; - height: $sidebar-footer-height; - position: fixed; - bottom: 0; - right: 0; - transition: margin $transition-sidebar; - padding: 1em; - - button { - width: 48%; - } - } - - @include breakpoint(tablet) { - .sidebar, .sidebar-footer { - width: $sidebar-medium-width; - margin-right: -$sidebar-medium-width; - } - } - - @include breakpoint(mobile) { - .sidebar, .sidebar-footer { - width: $sidebar-small-width; - margin-right: -$sidebar-small-width; - } - } - } - products { display: block; @@ -205,11 +124,13 @@ $sidebar-footer-height: 5em; .open-shop-message { a { - color: #0096ad; + color: $teal-500; - &:hover, &:focus, &:active { + &:hover, + &:focus, + &:active { text-decoration: none; - color: #4aadbd; + color: $teal-400; } } } @@ -231,10 +152,10 @@ $sidebar-footer-height: 5em; } } - .warning-sign { - margin: 0 10px 0 5px; - display: inline-block; - line-height: 1.9rem; +.warning-sign { + margin: 0 10px 0 5px; + display: inline-block; + line-height: 1.9rem; strong { color: $grey-650; @@ -256,3 +177,9 @@ $sidebar-footer-height: 5em; } } } + +.shop-filters-sidebar { + .property-selectors { + margin-bottom: $sidebar-footer-height + 2em; + } +} diff --git a/app/assets/stylesheets/darkswarm/shopping-cart.css.scss b/app/assets/stylesheets/darkswarm/shopping-cart.css.scss deleted file mode 100644 index d00f3915e7..0000000000 --- a/app/assets/stylesheets/darkswarm/shopping-cart.css.scss +++ /dev/null @@ -1,140 +0,0 @@ -@import "mixins"; -@import "branding"; -@import "compass/css3/user-interface"; -@import 'variables'; - -.cart { - @include user-select(none); - - .cart-span, .cart-span a { - display: inline-block; - } - - .cart-span { - float: left; - } - - .joyride-tip-guide { - display: block; - right: 0; - top: $topbar-height; - width: 480px; - - @media screen and (min-width: 641px) { - overflow-y: auto; - max-height: calc(95vh - 55px); - } - - @media screen and (max-width: 640px) { - width: 96%; - } - - .joyride-nub { - right: 22px !important; - left: auto; - } - - table { - width: 100%; - border: none; - border-spacing: 0px; - margin-bottom: 5px; - - tr.total-cart { - color: #fff; - background-color: #424242; - - td { - color: #fff; - } - } - - tr.product-cart { - background-color: #333333; - border-top: 1px solid #424242; - - td { - padding: 4px 12px; - color: #fff; - } - } - } - - .buttons { - margin-bottom: 0.1em; - - .button { - height: auto; - top: 0px; - } - } - } -} - -// Shopping cart -#update-cart { - #errorExplanation { - display: none; - } -} - -#cart-detail { - .cart-item-delete, .bought-item-delete { - a { - font-size: 1.125em; - } - } - - .out-of-stock { - color: $clr-brick; - } - - button, .button { - margin: 0; - } - - .toggle-bought { - cursor: pointer; - } - - tr.bought td { - color: $med-grey; - - h5 { - color: $med-grey; - } - - .already-confirmed { - float: right; - } - } - - input { - &.ng-invalid-stock, &.ng-invalid-number { - border: 1px solid $clr-brick; - } - } -} - -.item-thumb-image { - display: none; - - @media screen and (min-width: 640px) { - display: inline-block; - float: left; - padding-right: 0.5em; - width: 36px; - height: 36px; - } -} - -.links { - .button { - padding: 1.125rem 0 1.1875rem; - width: 210px; - - @media all and (max-width: 480px) { - width: 100%; - } - } -} diff --git a/app/assets/stylesheets/darkswarm/ui.css.scss b/app/assets/stylesheets/darkswarm/ui.css.scss index 66d72d6511..d6b0988ad6 100644 --- a/app/assets/stylesheets/darkswarm/ui.css.scss +++ b/app/assets/stylesheets/darkswarm/ui.css.scss @@ -124,7 +124,12 @@ button.success, .button.success { } } -button.large { +a.button.large { + line-height: 2.75em; +} + +button.large, +a.button.large { height: 3em; font-size: 1em; color: $white; @@ -158,3 +163,7 @@ button.large { padding-right: 0; padding-left: 0; } + +.disable-scroll { + overflow: hidden; +} diff --git a/app/assets/stylesheets/darkswarm/variables.css.scss b/app/assets/stylesheets/darkswarm/variables.css.scss index 115212fc76..08930efd76 100644 --- a/app/assets/stylesheets/darkswarm/variables.css.scss +++ b/app/assets/stylesheets/darkswarm/variables.css.scss @@ -33,6 +33,11 @@ $topbar-dropdown-link-bg-hover: $white; $mobile-nav-height: 2.8em; +$sidebar-small-width: 75%; +$sidebar-medium-width: 65%; +$sidebar-large-width: 45%; +$sidebar-footer-height: 5em; + $radius-small: 0.25em; $radius-medium: 0.5em; diff --git a/app/helpers/shop_helper.rb b/app/helpers/shop_helper.rb index a4c89bcd0d..8da650c4ef 100644 --- a/app/helpers/shop_helper.rb +++ b/app/helpers/shop_helper.rb @@ -50,4 +50,13 @@ module ShopHelper def no_open_order_cycles? @no_open_order_cycles ||= @order_cycles&.empty? end + + def show_shopping_cta? + return false if current_page?(main_app.shops_path) && current_distributor.blank? + + return false if current_distributor.present? && + current_page?(main_app.enterprise_shop_path(current_distributor)) + + true + end end diff --git a/app/serializers/api/variant_serializer.rb b/app/serializers/api/variant_serializer.rb index e824db8406..38cc649910 100644 --- a/app/serializers/api/variant_serializer.rb +++ b/app/serializers/api/variant_serializer.rb @@ -3,7 +3,7 @@ class Api::VariantSerializer < ActiveModel::Serializer :options_text, :unit_value, :unit_description, :unit_to_display, :display_as, :display_name, :name_to_display, :price, :on_demand, :on_hand, :fees, :price_with_fees, - :tag_list + :tag_list, :thumb_url delegate :price, to: :object @@ -30,4 +30,12 @@ class Api::VariantSerializer < ActiveModel::Serializer object.tag_list end + + def thumb_url + if object.product.images.present? + object.product.images.first.attachment.url(:mini) + else + "/assets/noimage/mini.png" + end + end end diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index fdf2cd4f17..f45b157a51 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -18,7 +18,7 @@ = stylesheet_link_tag "darkswarm/all" = csrf_meta_tags - %body{class: body_classes, ng: {app: "Darkswarm"}} + %body{class: body_classes, "body-scroll" => true , ng: {app: "Darkswarm"}} / [if lte IE 8] = render partial: "shared/ie_warning" = javascript_include_tag "iehack" diff --git a/app/views/shared/menu/_cart.html.haml b/app/views/shared/menu/_cart.html.haml index d6408dc634..1fd1b06e89 100644 --- a/app/views/shared/menu/_cart.html.haml +++ b/app/views/shared/menu/_cart.html.haml @@ -1,10 +1,8 @@ %span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"} - %a#cart.icon{"cart-toggle" => true} + %a#cart.icon{"ng-click" => "toggleCartSidebar()"} %span = t '.cart' %span.count %img{ src: image_path("menu/icn-cart.svg") } %span {{ Cart.total_item_count() }} - - = render 'shared/menu/joyride' diff --git a/app/views/shared/menu/_cart_sidebar.html.haml b/app/views/shared/menu/_cart_sidebar.html.haml new file mode 100644 index 0000000000..03c3f52222 --- /dev/null +++ b/app/views/shared/menu/_cart_sidebar.html.haml @@ -0,0 +1,44 @@ +.expanding-sidebar.cart-sidebar{ng: {controller: 'CartCtrl', show: 'showCartSidebar', class: "{'shown': showCartSidebar, 'hidden': !showCartSidebar}"}} + .background{ng: {click: 'toggleCartSidebar()'}} + .sidebar + .cart-header + %span.title{"ng-show" => "Cart.line_items.length == 1"} + = t('.items_in_cart_singular', num: "{{ Cart.total_item_count() }}") + %span.title{"ng-show" => "Cart.line_items.length > 1"} + = t('.items_in_cart_plural', num: "{{ Cart.total_item_count() }}") + %a.close{ng: {click: 'toggleCartSidebar()'}} + = t('.close') + %i.ofn-i_009-close + + .cart-content + %table + %tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"} + %td.image + %img{'ng-src' => '{{ line_item.variant.thumb_url }}'} + %td + %span {{ line_item.variant.extended_name | truncate: max_characters }} + %br + %span.options-text {{ line_item.variant.options_text | truncate: max_characters }} + %td.text-right + %span.quantity {{ line_item.quantity }} + %td + %span.total-price.right {{ line_item.total_price | localizeCurrency }} + + .cart-empty{"ng-show" => "Cart.line_items.length == 0"} + %p + = t('.cart_empty') + + %a.go-shopping.button.large.bright{ng: {show: "#{show_shopping_cta?}", href: "{{ CurrentHub.hub.id ? '#{main_app.shop_path}' : '#{main_app.shops_path}' }}"}} + = t('.take_me_shopping') + + .sidebar-footer{"ng-show" => "Cart.line_items.length > 0"} + %p.cart-total + %strong + = t 'total' + {{ Cart.total() | localizeCurrency }} + + %div.fullwidth + %a.edit-cart.button.large.dark.left{href: main_app.cart_path, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }"} + = "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t('.edit_cart')}' ) }}" + %a.checkout.button.large.bright.right{href: main_app.checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"} + = t '.checkout' diff --git a/app/views/shared/menu/_joyride.html.haml b/app/views/shared/menu/_joyride.html.haml deleted file mode 100644 index eb1875f383..0000000000 --- a/app/views/shared/menu/_joyride.html.haml +++ /dev/null @@ -1,63 +0,0 @@ -.cart-dropdown.joyride-tip-guide{"ng-class" => "{ in: open }", "ng-show" => "open"} - %span.joyride-nub.top - .joyride-content-wrapper - %h5 - = t 'cart_headline' - .buttons.text-right - %a.button.secondary.tiny.add_to_cart{ href: main_app.cart_path, type: :submit, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" } - = "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t(:cart_edit)}' ) }}" - %a.button.primary.tiny{href: main_app.checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"} - = t '.checkout' - %table - %tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"} - %td - %small - %strong - {{ line_item.variant.extended_name }} - %td.text-right - %small - %span.quantity {{ line_item.quantity }} - %i.ofn-i_009-close - %span.price {{ line_item.variant.price_with_fees | localizeCurrency }} - - %td - %small - \= - %strong - .total-price.right {{ line_item.total_price | localizeCurrency }} - - %table{"ng-show" => "Cart.line_items.length > 0"} - %tr.total-cart - %td - %em - = t 'total' - \: - %td.text-right - %strong {{ Cart.total() | localizeCurrency }} - - .buttons.text-right - %a.button.secondary.tiny.add_to_cart{ href: main_app.cart_path, type: :submit, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" } - = "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t(:cart_edit)}' ) }}" - %a.button.primary.tiny{href: main_app.checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"} - = t '.checkout' - - if order_changes_allowed? - %h5{"ng-if" => "Cart.line_items_finalised.length", style: 'margin-top: 1em'} - = t '.already_ordered_products' - %table - %tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_finalised", - "id" => "cart-variant-{{ line_item.variant.id }}"} - %td - %small - %strong - {{ line_item.variant.extended_name }} - %td.text-right - %small - %span.quantity {{ line_item.quantity }} - %i.ofn-i_009-close - %span.price {{ line_item.variant.price_with_fees | localizeCurrency }} - - %td - %small - \= - %strong - .total-price.right {{ line_item.total_price | localizeCurrency }} \ No newline at end of file diff --git a/app/views/shared/menu/_menu.html.haml b/app/views/shared/menu/_menu.html.haml index 050a3f043e..4559434a8f 100644 --- a/app/views/shared/menu/_menu.html.haml +++ b/app/views/shared/menu/_menu.html.haml @@ -1,4 +1,6 @@ -= render "shared/menu/large_menu" -%ofn-flash -= render "shared/menu/mobile_menu" -= render "shared/menu/offcanvas_menu" +%div{'ng-controller' => 'CartDropdownCtrl'} + = render "shared/menu/large_menu" + %ofn-flash + = render "shared/menu/mobile_menu" + = render "shared/menu/offcanvas_menu" + = render "shared/menu/cart_sidebar" diff --git a/app/views/shared/menu/_mobile_menu.html.haml b/app/views/shared/menu/_mobile_menu.html.haml index 8ef5ef7b5d..716db01f73 100644 --- a/app/views/shared/menu/_mobile_menu.html.haml +++ b/app/views/shared/menu/_mobile_menu.html.haml @@ -1,7 +1,7 @@ %nav.tab-bar.show-for-medium-down %section.left %a.left-off-canvas-toggle.menu-icon - %span + = image_tag "menu/btn-menu-mobile.png" %section.left .ofn-logo @@ -9,12 +9,12 @@ %img{src: ContentConfig.logo_mobile.url, srcset: ContentConfig.logo_mobile_svg.url, width: "75", height: "26"} %section.right{"ng-cloak" => true} - %span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"} - %a.icon{href: main_app.cart_path} + %span.cart-span{"ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"} + %a.icon{ng: {click: 'toggleCartSidebar()'}} %span = t '.cart' %span.count - %img{ src: image_path("menu/icn-cart.svg") } + = image_tag "menu/icn-cart.svg" %span {{ Cart.total_item_count() }} diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 7d2718c2d5..ffbc7bdf25 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -31,7 +31,7 @@ = render partial: "shop/products/filters" - .shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}} + .expanding-sidebar.shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}} .background{ng: {click: 'toggleFilterSidebar()'}} .sidebar %h5 diff --git a/app/views/spree/orders/form/_cart_links.html.haml b/app/views/spree/orders/form/_cart_links.html.haml index 798a428f7c..89a63d70fd 100644 --- a/app/views/spree/orders/form/_cart_links.html.haml +++ b/app/views/spree/orders/form/_cart_links.html.haml @@ -1,5 +1,5 @@ .row.links{'data-hook' => "cart_buttons"} - %a.continue-shopping.button.large.secondary{href: current_shop_products_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true} + %a.continue-shopping.button.secondary{href: current_shop_products_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true} = t :orders_edit_continue - %a#checkout-link.button.large.primary.right{href: main_app.checkout_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true} + %a#checkout-link.button.primary.right{href: main_app.checkout_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true} = t :orders_edit_checkout diff --git a/config/locales/en.yml b/config/locales/en.yml index 5b89620b2b..27cf49f93b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1216,13 +1216,18 @@ en: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit cart" + items_in_cart_singular: "%{num} item in your cart" + items_in_cart_plural: "%{num} items in your cart" + close: "Close" + cart_empty: "Your cart is empty" + take_me_shopping: "Take me shopping!" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - checkout: "Checkout now" - already_ordered_products: "Already ordered in this order cycle" register_call: selling_on_ofn: "Interested in getting on the Open Food Network?" register: "Register here" diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index 9068504be6..e7785dcdb4 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -282,11 +282,6 @@ feature "full-page cart", js: true do expect(page).to have_no_content item1.variant.name expect(page).to have_content item2.variant.name - # open the dropdown cart and check there as well - find('#cart').click - expect(page).to have_no_content item1.variant.name - expect(page).to have_content item2.variant.name - visit main_app.cart_path find("td.toggle-bought").click diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index e1679791d4..0093afe405 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -105,8 +105,9 @@ feature "As a consumer I want to shop with a distributor", js: true do # -- Cart shows correct price fill_in "variants[#{variant.id}]", with: 1 - show_cart - within("li.cart") { expect(page).to have_content with_currency(1020.99) } + toggle_cart + within(".cart-sidebar") { expect(page).to have_content with_currency(1020.99) } + toggle_cart # -- Changing order cycle accept_alert do @@ -119,8 +120,9 @@ feature "As a consumer I want to shop with a distributor", js: true do # that we are not filling in the quantity on the outgoing row expect(page).not_to have_selector "tr.product-cart" within('product:not(.ng-leave)') { fill_in "variants[#{variant.id}]", with: 1 } - show_cart - within("li.cart") { expect(page).to have_content with_currency(19.99) } + + wait_for_cart + within(".cart-sidebar") { expect(page).to have_content with_currency(19.99) } end describe "declining to clear the cart" do @@ -136,9 +138,9 @@ feature "As a consumer I want to shop with a distributor", js: true do it "leaves the cart untouched when the user declines" do handle_js_confirm(false) do select "frogs", from: "order_cycle_id" - show_cart + toggle_cart expect(page).to have_selector "tr.product-cart" - expect(page).to have_selector 'li.cart', text: '1' + expect(page).to have_selector '.cart-sidebar', text: '1' # The order cycle choice should not have changed expect(page).to have_select 'order_cycle_id', selected: 'turtles' @@ -156,21 +158,6 @@ feature "As a consumer I want to shop with a distributor", js: true do quick_login_as order.user visit shop_path end - - it "shows previous orders if order cycle was selected already" do - select "frogs", from: "order_cycle_id" - expect(page).to have_content "Next order closing in 2 days" - visit shop_path - find("#cart").click - expect(page).to have_text(I18n.t("shared.menu.joyride.already_ordered_products")) - end - - it "shows previous orders after selecting an order cycle" do - select "frogs", from: "order_cycle_id" - expect(page).to have_content "Next order closing in 2 days" - find("#cart").click - expect(page).to have_text(I18n.t("shared.menu.joyride.already_ordered_products")) - end end end end @@ -294,7 +281,7 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(li.quantity).to eq(1) fill_in "variants[#{variant.id}]", with: '0' - within('li.cart') { expect(page).not_to have_content product.name } + within('.cart-sidebar') { expect(page).not_to have_content product.name } wait_until { !cart_dirty } expect(Spree::LineItem.where(id: li)).to be_empty diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index a4279786da..6dfed074a7 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -67,8 +67,8 @@ feature "shopping with variant overrides defined", js: true do it "shows the correct prices when products are in the cart" do fill_in "variants[#{product1_variant1.id}]", with: "2" - show_cart - wait_until_enabled 'li.cart a.button' + toggle_cart + wait_until_enabled '.cart-sidebar a.edit-cart' visit shop_path expect(page).to have_price with_currency(61.11) end @@ -78,9 +78,8 @@ feature "shopping with variant overrides defined", js: true do it "shows the overridden price with fees in the quick cart" do fill_in "variants[#{product1_variant1.id}]", with: "2" - show_cart + toggle_cart expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .quantity", text: '2' - expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .price", text: with_currency(61.11) expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .total-price", text: with_currency(122.22) end @@ -202,8 +201,8 @@ feature "shopping with variant overrides defined", js: true do end def click_checkout - show_cart - wait_until_enabled 'li.cart a.button' - first(:link, 'Checkout now').click + toggle_cart + wait_until_enabled '.cart-sidebar a.edit-cart' + first(:link, I18n.t('shared.menu.cart_sidebar.checkout')).click end end diff --git a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee index 408fecf7ea..2d9d1452f3 100644 --- a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee @@ -49,25 +49,9 @@ describe 'Variants service', -> variant = {product_name: 'product_name', name_to_display: 'product_name'} expect(Variants.extendedVariantName(variant)).toEqual "product_name" - it "includes the options text even if variant name is same as product", -> - variant = - product_name: 'product_name' - name_to_display: 'product_name' - options_text: 'options_text' - - expect(Variants.extendedVariantName(variant)).toEqual "product_name (options_text)" - describe "when the product name and the variant name differ", -> it "returns a combined name when there is no options text", -> variant = product_name: 'product_name' name_to_display: 'name_to_display' expect(Variants.extendedVariantName(variant)).toEqual "product_name - name_to_display" - - it "returns a combined name when there is some options text", -> - variant = - product_name: 'product_name' - name_to_display: 'name_to_display' - options_text: 'options_text' - - expect(Variants.extendedVariantName(variant)).toEqual "product_name - name_to_display (options_text)" diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index cde1437b04..e5123715e0 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -1,17 +1,17 @@ module ShopWorkflow def wait_for_cart first("#cart").click - within '.cart-dropdown' do + within '.cart-sidebar' do expect(page).to_not have_link "Updating cart..." end end def edit_cart wait_for_cart - within '.cart-dropdown' do - expect(page).to have_link "Edit your cart" + within '.cart-sidebar' do + expect(page).to have_link I18n.t('shared.menu.cart_sidebar.edit_cart') end - first("a.add_to_cart").click + first("a.edit-cart").click end def have_price(price) diff --git a/spec/support/request/ui_component_helper.rb b/spec/support/request/ui_component_helper.rb index 277d8ee88c..b23002e3d7 100644 --- a/spec/support/request/ui_component_helper.rb +++ b/spec/support/request/ui_component_helper.rb @@ -59,13 +59,13 @@ module UIComponentHelper end def have_in_cart(name) - show_cart - within "li.cart" do + toggle_cart + within ".cart-sidebar" do have_content name end end - def show_cart + def toggle_cart page.find("#cart").click end