mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #5480 from Matt-Yorkley/mobile-cart-restyle
[Mobile] Cart Dropdown
This commit is contained in:
@@ -16,6 +16,10 @@ plugins:
|
||||
enabled: false
|
||||
PropertySortOrder:
|
||||
enabled: false
|
||||
StringQuotes:
|
||||
enabled: false
|
||||
DeclarationOrder:
|
||||
enabled: false
|
||||
duplication:
|
||||
enabled: true
|
||||
exclude_patterns:
|
||||
|
||||
BIN
app/assets/images/menu/btn-menu-mobile.png
Normal file
BIN
app/assets/images/menu/btn-menu-mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 759 B |
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.controller "CartDropdownCtrl", ($scope, Cart, BodyScroll) ->
|
||||
$scope.Cart = Cart
|
||||
$scope.showCartSidebar = false
|
||||
|
||||
$scope.toggleCartSidebar = ->
|
||||
$scope.showCartSidebar = !$scope.showCartSidebar
|
||||
BodyScroll.toggle()
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
angular.module("Darkswarm").factory "BodyScroll", ($rootScope) ->
|
||||
new class BodyScroll
|
||||
disabled: false
|
||||
|
||||
toggle: ->
|
||||
@disabled = !@disabled
|
||||
$rootScope.$broadcast "toggleBodyScroll"
|
||||
@@ -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) ->
|
||||
|
||||
124
app/assets/stylesheets/darkswarm/cart-dropdown.css.scss
Normal file
124
app/assets/stylesheets/darkswarm/cart-dropdown.css.scss
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
75
app/assets/stylesheets/darkswarm/cart-page.css.scss
Normal file
75
app/assets/stylesheets/darkswarm/cart-page.css.scss
Normal file
@@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss
Normal file
79
app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'
|
||||
|
||||
44
app/views/shared/menu/_cart_sidebar.html.haml
Normal file
44
app/views/shared/menu/_cart_sidebar.html.haml
Normal file
@@ -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'
|
||||
@@ -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 }}
|
||||
@@ -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"
|
||||
|
||||
@@ -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() }}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user