diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f000c8c4..d9f26dcd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -51,6 +51,8 @@ jobs:
- name: Build
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' }}
uses: VirtoCommerce/vc-github-actions/build-theme@master
+ with:
+ versionSuffix: ${{ steps.image.outputs.suffix }}
- name: Publish
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' }}
@@ -76,4 +78,4 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ steps.publish.outputs.artifactPath }}
asset_name: ${{ steps.publish.outputs.artifactName }}
- asset_content_type: application/zip
\ No newline at end of file
+ asset_content_type: application/zip
diff --git a/assets/js/account/account-orders.js b/assets/js/account/account-orders.js
index 10da1a19..f7da90b6 100644
--- a/assets/js/account/account-orders.js
+++ b/assets/js/account/account-orders.js
@@ -125,6 +125,36 @@ angular.module('storefront.account')
$window.open(url, '_blank');
}
+ // $ctrl.reorder = function() {
+ // var productIdsQuery = $ctrl.order.items.map(item => {
+ // return 'productIds=' + item.productId;
+ // }).join("&");
+
+ // catalogService.getProducts(productIdsQuery).then(response => {
+ // if (response.data && response.data.length) {
+ // var configurationProducts = response.data.map(item => {
+ // return angular.extend(item, { quantity: _.findWhere($ctrl.order.items, {productId: item.id}).quantity });
+ // });
+ // var inventoryError = configurationProducts.some(product => {
+ // return product.availableQuantity < product.quantity;
+ // });
+ // var dialogData = toDialogDataModel(configurationProducts, null, inventoryError, null);
+ // dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
+ // if (!inventoryError) {
+ // var items = configurationProducts.map(product => {
+ // return { id: product.id, quantity: product.quantity };
+ // });
+ // cartService.addLineItems(items).then(res => {
+ // var result = res.data;
+ // if (result.isSuccess) {
+ // $rootScope.$broadcast('cartItemsChanged');
+ // }
+ // });
+ // }
+ // }
+ // });
+ // }
+
$ctrl.paymentMethodChanged = function () {
loader.wrapLoading(function() {
$ctrl.selectedPaymentMethod = _.find($ctrl.paymentMethods, function (pm) { return pm.code == $ctrl.selectedPaymentMethodCode; });
@@ -165,6 +195,11 @@ angular.module('storefront.account')
addProductToCartById(productId, quantity);
});
+ $scope.$on('configurationAdded', function (event, data) {
+ const {configuration} = data;
+ addConfigurationToCart(configuration);
+ });
+
var components = [];
$ctrl.addComponent = function (component) {
components.push(component);
@@ -188,7 +223,7 @@ angular.module('storefront.account')
};
function addProductToCartById(productId, quantity) {
- catalogService.getProduct([productId]).then(function (response) {
+ catalogService.getProduct([productId]).then(response => {
if (response.data && response.data.length) {
var product = response.data[0];
addProductToCart(product, quantity);
@@ -196,17 +231,58 @@ angular.module('storefront.account')
});
}
- function addProductToCart(product, quantity) {
- var dialogData = toDialogDataModel(product, quantity);
- dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl');
- cartService.addLineItem(product.id, quantity).then(function (response) {
- $rootScope.$broadcast('cartItemsChanged');
+ function addConfigurationToCart(configuration) {
+ let productIdsQuery = configuration.items.map(item => {
+ return 'productIds=' + item.productId;
+ }).join("&");
+
+ catalogService.getProducts(productIdsQuery).then(response => {
+ if (response.data && response.data.length) {
+ let configurationProducts = response.data.map(item => {
+ return angular.extend(item, { quantity: _.findWhere(configuration.items, {productId: item.id}).quantity });
+ });
+ let inventoryError = configurationProducts.some(product => {
+ return product.availableQuantity < product.quantity;
+ });
+ let dialogData = toDialogDataModel(configurationProducts, configuration.quantity, inventoryError, configuration.productId);
+ dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
+ if (!inventoryError) {
+ let items = configurationProducts.map(product => {
+ return { id: product.id, quantity: product.quantity, configuredProductId: configuration.productId };
+ });
+ cartService.addLineItems(items).then(res => {
+ let result = res.data;
+ if (result.isSuccess) {
+ $rootScope.$broadcast('cartItemsChanged');
+ }
+ });
+ }
+ }
});
}
- function toDialogDataModel(product, quantity) {
- return { items: [angular.extend({ }, product, { quantity: quantity })] };
+ function addProductToCart(product, quantity) {
+ var inventoryError = product.availableQuantity < quantity;
+ angular.extend(product, { quantity });
+ var dialogData = toDialogDataModel([product], null, inventoryError, null);
+ dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
+ if (!inventoryError) {
+ cartService.addLineItem(product.id, quantity).then(() => {
+ $rootScope.$broadcast('cartItemsChanged');
+ });
+ }
+ }
+
+ function toDialogDataModel(products, configurationQty, inventoryError, configuredProductId) {
+ let productIds = products.map(product => {
+ return product.productId;
+ });
+ let items = products.map(product => {
+ return angular.extend({ }, product, { inventoryError: product.availableQuantity < product.quantity, configuredProductId: configuredProductId })
+ });
+ return { productIds, items, inventoryError, configuredProductId, configurationQty };
}
+
}]
})
.filter('orderToSummarizedStatusLabel', [function () {
diff --git a/assets/js/account/account-orders.tpl.liquid b/assets/js/account/account-orders.tpl.liquid
index 711e957c..d4ca3a61 100644
--- a/assets/js/account/account-orders.tpl.liquid
+++ b/assets/js/account/account-orders.tpl.liquid
@@ -75,7 +75,7 @@
{% capture order_number %}{% raw %}{{$ctrl.orderNumber}}{% endraw %}{% endcapture %}
-
{{ 'customer.order.title' | t: order_number }}
+
{{ 'customer.order.title' | t: order_number }}
{{ 'customer.orders.status' | t }}:
@@ -98,11 +98,9 @@
-
-
diff --git a/assets/js/app/consts.js.liquid b/assets/js/app/consts.js.liquid
index a0dc21e5..61391bdf 100644
--- a/assets/js/app/consts.js.liquid
+++ b/assets/js/app/consts.js.liquid
@@ -10,6 +10,7 @@ angular.module('storefrontApp.consts', [])
.constant('sortAscending', 'asc')
.constant('sortDescending', 'desc')
.constant('orderStatuses', ['Unpaid','Paid','Completed'])
+.constant('storeCurrency', {{ current_currency | json }})
.constant('itemResponseGroup', {
None: 0,
ItemInfo: 1,
diff --git a/assets/js/checkout/checkout-configurable-line-item.js b/assets/js/checkout/checkout-configurable-line-item.js
index 73b5c870..c7057351 100644
--- a/assets/js/checkout/checkout-configurable-line-item.js
+++ b/assets/js/checkout/checkout-configurable-line-item.js
@@ -8,8 +8,7 @@ storefrontApp.component('vcCheckoutConfigurableLineItem', {
bindings: {
item: '=',
onChangeQty: '&',
- onRemove: '&',
- cartItems: '<'
+ onRemove: '&'
},
controller: ['$scope', 'availablePaymentPlans', 'baseUrl', function ($scope, availablePaymentPlans, baseUrl) {
var ctrl = this;
@@ -28,12 +27,12 @@ storefrontApp.component('vcCheckoutConfigurableLineItem', {
this.changeQty = function () {
if (ctrl.onChangeQty) {
- ctrl.onChangeQty({ item: ctrl.item.configuredLineItem });
+ ctrl.onChangeQty({ item: ctrl.item });
}
};
this.remove = function () {
- ctrl.onRemove({ item: ctrl.item.configuredLineItem });
+ ctrl.onRemove({ item: ctrl.item });
}
this.validate = function () {
@@ -53,7 +52,7 @@ storefrontApp.component('vcCheckoutConfigurableLineItem', {
function getConfiguredLineItems(item) {
_.each(item.parts, function (part) {
- part.items = [ctrl.cartItems.find(x => x.id === part.selectedItemId)];
+ part.items = [item.items.find(x => x.id === part.selectedItemId)];
});
}
diff --git a/assets/js/checkout/checkout-configurable-line-item.tpl.html.liquid b/assets/js/checkout/checkout-configurable-line-item.tpl.html.liquid
index c5483db4..e110892e 100644
--- a/assets/js/checkout/checkout-configurable-line-item.tpl.html.liquid
+++ b/assets/js/checkout/checkout-configurable-line-item.tpl.html.liquid
@@ -1,33 +1,33 @@
-
+
-
-
Item
+
+
Item
Price
{% if settings.show_prices_with_taxes %}
-
+
{% else %}
-
+
{% endif %}
/ each
-
+
-
-
-
+
+
+
-
+
Update
@@ -39,9 +39,9 @@
Total
{% if settings.show_prices_with_taxes %}
-
+
{% else %}
-
+
{% endif %}
@@ -86,9 +86,9 @@
|
{% if settings.show_prices_with_taxes %}
-
|
+
|
{% else %}
-
|
+
|
{% endif %}
diff --git a/assets/js/checkout/checkout.js b/assets/js/checkout/checkout.js
index 25841a5c..4e9d4a5b 100644
--- a/assets/js/checkout/checkout.js
+++ b/assets/js/checkout/checkout.js
@@ -178,7 +178,7 @@ angular.module(moduleName, ['credit-cards', 'angular.filter'])
$scope.checkout.cart = cart;
if (!$scope.checkout.productIds) {
- $scope.checkout.productIds = cart.items.map(lineItem => lineItem.productId);
+ $scope.checkout.productIds = cart.usualItems.map(lineItem => lineItem.productId);
}
if (cart.coupon) {
@@ -189,21 +189,6 @@ angular.module(moduleName, ['credit-cards', 'angular.filter'])
$scope.checkout.coupon.code = null;
}
- if (cart.configuredItems && cart.configuredItems.length) {
- $scope.configuredItemsIds = [];
- _.each($scope.checkout.cart.configuredItems, function (item) {
- _.each(item.parts, function (part) {
- $scope.configuredItemsIds.push(part.selectedItemId);
- });
- });
- $scope.configuredItemsIds = _.uniq($scope.configuredItemsIds);
- $scope.regularLineItems = _.filter($scope.checkout.cart.items, function(item) {
- return $scope.configuredItemsIds.indexOf(item.id) === -1;
- });
- } else {
- $scope.regularLineItems = $scope.checkout.cart.items;
- }
-
if (cart.payments.length) {
$scope.checkout.payment = cart.payments[0];
$scope.checkout.paymentMethod.code = $scope.checkout.payment.paymentGatewayCode;
diff --git a/assets/js/common-components/lineItems.js b/assets/js/common-components/lineItems.js
index 0b678c61..1447ca25 100644
--- a/assets/js/common-components/lineItems.js
+++ b/assets/js/common-components/lineItems.js
@@ -3,13 +3,43 @@
storefrontApp.component('vcLineItems', {
templateUrl: "themes/assets/js/common-components/lineItems.tpl.liquid",
bindings: {
- items: '='
+ order: '='
},
- controller: ['$scope', function ($scope) {
+ controller: ['$scope', 'baseUrl', function ($scope, baseUrl) {
+ var $ctrl = this;
+ $scope.baseUrl = baseUrl;
+ $scope.regex = new RegExp(/^\/+/);
- $scope.addProductToCart = function (productId, quantity) {
+ $ctrl.addProductToCart = function (productId, quantity) {
$scope.$emit('lineItemAdded', {productId, quantity});
}
+ $ctrl.addConfigurationToCart = function (configuration) {
+ $scope.$emit('configurationAdded', {configuration});
+ }
+
+ $ctrl.getToggleTitle = function (group) {
+ return group.showConfiguration === false ? 'Show configuration' : 'Hide configuration';
+ };
+
+ $ctrl.toggleConfiguration = function(group) {
+ group.showConfiguration = !group.showConfiguration;
+ };
+
+ $ctrl.getProductLink = function(productId) {
+ return `product/${productId}`.replace($scope.regex, $scope.baseUrl);
+ };
+
+ function getConfiguredLineItems(groups) {
+ _.each(groups, group => {
+ angular.extend(group, { showConfiguration: false });
+ _.each(group.parts, part => {
+ part.items = [group.items.find(x => x.id === part.selectedItemId)];
+ });
+ });
+ }
+
+ getConfiguredLineItems($ctrl.order.configuredGroups);
+
}]
});
diff --git a/assets/js/common-components/lineItems.tpl.liquid b/assets/js/common-components/lineItems.tpl.liquid
index 3d74f766..4b03aca3 100644
--- a/assets/js/common-components/lineItems.tpl.liquid
+++ b/assets/js/common-components/lineItems.tpl.liquid
@@ -1,30 +1,101 @@
-
+
{{ 'customer.order.product' | t }} |
|
- {{ 'customer.order.quantity' | t }} |
- {{ 'customer.order.total' | t }} |
+ {{ 'customer.order.quantity' | t }} |
+ {{ 'customer.order.total' | t }} |
|
+
+
+
+
+ |
+
+
+
+
+
+
+ |
+
+
+ |
+
+ {% if settings.show_prices_with_taxes %}
+
+
+ {% else %}
+
+
+ {% endif %}
+ |
+
+
+
+
+ |
+
+
+ |
+
+
+
+
+
+ Configuration parts
+
+
+
+
+
+
+ |
+ Product |
+ Quantity |
+ Total |
+
+
+
+
+
+
+ |
+
+
+ |
+ |
+ {% if settings.show_prices_with_taxes %}
+ |
+ {% else %}
+ |
+ {% endif %}
+
+
+
+
+ |
+
+
-
-
-
+ |
+
+
|
-
+
{% if shop.subscription_enabled %}
{% endif %}
|
-
+ |
|
-
+ |
{% if settings.show_prices_with_taxes %}
@@ -35,7 +106,7 @@
|
-
+
|
diff --git a/assets/js/product.js b/assets/js/product.js
index ce55c2db..827ad398 100644
--- a/assets/js/product.js
+++ b/assets/js/product.js
@@ -1,7 +1,7 @@
var storefrontApp = angular.module('storefrontApp');
-storefrontApp.controller('productController', ['$rootScope', '$scope', '$window', '$timeout', 'dialogService', 'catalogService', 'cartService', 'quoteRequestService', 'availabilityService', '$filter', 'roundHelper', 'validationHelper',
- function ($rootScope, $scope, $window, $timeout, dialogService, catalogService, cartService, quoteRequestService, availabilityService, $filter, roundHelper, validationHelper) {
+storefrontApp.controller('productController', ['$rootScope', '$scope', '$window', '$timeout', 'dialogService', 'catalogService', 'cartService', 'quoteRequestService', 'availabilityService', '$filter', 'roundHelper', 'validationHelper', 'storeCurrency',
+ function ($rootScope, $scope, $window, $timeout, dialogService, catalogService, cartService, quoteRequestService, availabilityService, $filter, roundHelper, validationHelper, storeCurrency) {
//TODO: prevent add to cart not selected variation
// display validator please select property
// display price range
@@ -22,31 +22,40 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
}
var configuredProductId = $window.product.id;
-
- var items = $scope.productParts.map(function(value){
- return { id: value.selectedItemId, quantity: $scope.configurationQty, configuredProductId: configuredProductId };
+ var products = $scope.productParts.map(function(part) {
+ return part.items.find(function(item) {
+ return item.id === part.selectedItemId;
+ });
});
- cartService.addLineItems(items).then(function (response) {
- var result = response.data;
- if(result.isSuccess) {
- $rootScope.$broadcast('cartItemsChanged');
- var products = $scope.productParts.map(function(part){
- return part.items.find(function(item){
- return item.id === part.selectedItemId;
- });
- });
-
- var dialogData = toDialogDataModel(products, $scope.configurationQty);
- dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
- }
+ var inventoryError = products.some(product => {
+ return product.availableQuantity < $scope.configurationQty;
});
+ var dialogData = toDialogDataModel(products, $scope.configurationQty, inventoryError, configuredProductId);
+ dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
+
+ if (!inventoryError) {
+ var items = $scope.productParts.map(function(value) {
+ return { id: value.selectedItemId, quantity: $scope.configurationQty, configuredProductId: configuredProductId };
+ });
+
+ cartService.addLineItems(items).then(function (response) {
+ var result = response.data;
+ if (result.isSuccess) {
+ $rootScope.$broadcast('cartItemsChanged');
+ }
+ });
+ }
}
+
$scope.addProductToCart = function (product, quantity) {
- var dialogData = toDialogDataModel([product], quantity);
+ var inventoryError = product.availableQuantity < quantity;
+ var dialogData = toDialogDataModel([product], quantity, inventoryError, null);
dialogService.showDialog(dialogData, 'recentlyAddedCartItemDialogController', 'storefront.recently-added-cart-item-dialog.tpl', 'lg');
- cartService.addLineItem(product.id, quantity).then(function (response) {
- $rootScope.$broadcast('cartItemsChanged');
- });
+ if (!inventoryError) {
+ cartService.addLineItem(product.id, quantity).then(() => {
+ $rootScope.$broadcast('cartItemsChanged');
+ });
+ }
}
$scope.addProductToCartById = function (productId, quantity, event) {
@@ -90,15 +99,15 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
total = roundHelper.bankersRound($scope.defaultPrice * $scope.configurationQty);
}
- return $filter('currency')(total ,'$');
+ return $filter('currency')(total, storeCurrency.symbol);
}
$scope.getDefaultPrice = function() {
- return $filter('currency')($scope.defaultPrice, '$');
+ return $filter('currency')($scope.defaultPrice, storeCurrency.symbol);
}
$scope.getCustomChangesTotal = function() {
- return $scope.differenceSign + $filter('currency')($scope.totalDifference, '$') || $filter('currency')(0, '$');
+ return $scope.differenceSign + $filter('currency')($scope.totalDifference, storeCurrency.symbol) || $filter('currency')(0, storeCurrency.symbol);
}
$scope.quantityChanged = function(qty) {
@@ -111,14 +120,14 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
}
}
- function toDialogDataModel(products, quantity) {
+ function toDialogDataModel(products, quantity, inventoryError, configuredProductId) {
let productIds = products.map(function(product) {
return product.id;
});
let items = products.map(function(product) {
- return angular.extend({ }, product, { quantity: quantity })
+ return angular.extend({ }, product, { quantity: +quantity, inventoryError: product.availableQuantity < quantity, configuredProductId: configuredProductId })
});
- return { productIds: productIds, items: items };
+ return { productIds, items, inventoryError, configuredProductId, configurationQty: quantity };
}
function initialize(filters) {
@@ -157,14 +166,7 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
});
});
- catalogService.getProductConfiguration(product.id).then(function(response) {
- $scope.productParts = response.data;
- $scope.defaultProductParts = [];
- _.each($scope.productParts, function (part) {
- $scope.defaultProductParts.push(part.items.find(x => x.id === part.selectedItemId));
- });
- $scope.defaultPrice = roundHelper.bankersRound($scope.defaultProductParts.reduce((prev, cur) => prev + cur.price.actualPrice.amount, 0));
- });
+ $scope.initProductConfiguration(product.id);
};
function getFlatternDistinctPropertiesMap(variations) {
@@ -217,6 +219,18 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
($scope.updatedTotal > $scope.defaultPrice) ? '+' : '-';
}
+ $scope.initProductConfiguration = function(productId) {
+ catalogService.getProductConfiguration(productId).then(function(response) {
+ $scope.productParts = response.data;
+ $scope.defaultProductParts = [];
+ _.each($scope.productParts, function (part) {
+ $scope.defaultProductParts.push(part.items.find(x => x.id === part.selectedItemId));
+ });
+
+ $scope.defaultPrice = roundHelper.bankersRound($scope.defaultProductParts.reduce((prev, cur) => prev + cur.price.actualPrice.amount, 0));
+ });
+ }
+
$scope.sendToEmail = function (storeId, productId, productUrl, language) {
dialogService.showDialog({ storeId: storeId, productId: productId, productUrl: productUrl, language: language }, 'recentlyAddedCartItemDialogController', 'storefront.send-product-to-email.tpl');
};
@@ -224,8 +238,8 @@ storefrontApp.controller('productController', ['$rootScope', '$scope', '$window'
$scope.$watch('filters', initialize);
}]);
-storefrontApp.controller('recentlyAddedCartItemDialogController', ['$scope', '$window', '$uibModalInstance', 'mailingService', 'dialogData', 'baseUrl', function ($scope, $window, $uibModalInstance, mailingService, dialogData, baseUrl) {
- $scope.dialogData = dialogData;
+storefrontApp.controller('recentlyAddedCartItemDialogController', ['$rootScope', '$scope', '$window', '$uibModalInstance', 'mailingService', 'dialogData', 'baseUrl', 'cartService', 'roundHelper', '$filter', 'storeCurrency', function ($rootScope, $scope, $window, $uibModalInstance, mailingService, dialogData, baseUrl, cartService, roundHelper, $filter, storeCurrency) {
+ $scope.dialogData = dialogData || {};
$scope.baseUrl = baseUrl;
$scope.regex = new RegExp(/^\/+/);
@@ -233,17 +247,91 @@ storefrontApp.controller('recentlyAddedCartItemDialogController', ['$scope', '$w
$uibModalInstance.dismiss('cancel');
}
+ $scope.addToCart = function() {
+ $scope.dialogData.inventoryError = false;
+ if ($scope.dialogData && $scope.dialogData.items && $scope.dialogData.items.length === 1) {
+ cartService.addLineItem($scope.dialogData.items[0].id, $scope.dialogData.items[0].quantity).then(() => {
+ $rootScope.$broadcast('cartItemsChanged');
+ });
+ } else if ($scope.dialogData.configuredProductId) {
+ let items = $scope.dialogData.items.map(item => {
+ return { id: item.id, quantity: $scope.configurationQty, configuredProductId: item.configuredProductId };
+ });
+ cartService.addLineItems(items).then(response => {
+ let result = response.data;
+ if (result.isSuccess) {
+ $rootScope.$broadcast('cartItemsChanged');
+ }
+ });
+ } else {
+ let items = $scope.dialogData.items.map(item => {
+ return { id: item.id, quantity: item.quantity };
+ });
+ cartService.addLineItems(items).then(response => {
+ let result = response.data;
+ if (result.isSuccess) {
+ $rootScope.$broadcast('cartItemsChanged');
+ }
+ });
+ }
+ }
+
+ $scope.calculateTotal = function(itemPrice, itemQuantity) {
+ var total = roundHelper.bankersRound(itemPrice * itemQuantity);
+ return $filter('currency')(total, storeCurrency.symbol);
+ }
+
+ $scope.setInitQuantity = function(item) {
+ if (item.inventoryError) {
+ return item.availableQuantity;
+ } else {
+ return item.quantity;
+ }
+ }
+
+ $scope.getConfirmationTitle = function() {
+ if ($scope.dialogData && $scope.dialogData.items && $scope.dialogData.items.length === 1) {
+ return '1 item was added to cart';
+ } else {
+ return `${$scope.dialogData.items.length} items were added to cart`;
+ }
+ }
+
+ $scope.quantityChanged = function(qty) {
+ $scope.configurationQty = qty;
+ }
+
$scope.redirect = function (url) {
$window.location.href = url;
}
+
$scope.send = function(email) {
mailingService.sendProduct(dialogData.productId, { email: email, storeId: dialogData.storeId, productUrl: dialogData.productUrl, language: dialogData.language });
$uibModalInstance.close();
}
+
+ function getMaxInventory() {
+ var inventoryArray = $scope.dialogData.items.map(item => {
+ return item.availableQuantity;
+ });
+ $scope.maxConfigurationQty = Math.min(...inventoryArray);
+ $scope.configurationQty = $scope.maxConfigurationQty;
+ }
+
+ function initialize() {
+ if ($scope.dialogData.inventoryError && $scope.dialogData.configuredProductId) {
+ getMaxInventory();
+ } else if (!$scope.dialogData.inventoryError && $scope.dialogData.configuredProductId) {
+ $scope.configurationQty = $scope.dialogData.configurationQty;
+ }
+ }
+
+ initialize();
+
}]);
storefrontApp.controller('changeConfigurationGroupItemDialogController', ['$scope', '$window', '$uibModalInstance', 'dialogData', function ($scope, $window, $uibModalInstance, dialogData) {
- $scope.dialogData = dialogData;
+ $scope.dialogData = dialogData || {};
$scope.selectedId = dialogData.selectedItemId;
$scope.close = function() {
diff --git a/assets/scss/_custom.scss b/assets/scss/_custom.scss
index c8aeb552..69f693a3 100644
--- a/assets/scss/_custom.scss
+++ b/assets/scss/_custom.scss
@@ -3,7 +3,6 @@
@import "mixins/custom/_buttons.scss";
@import "mixins/custom/_button-groups.scss";
@import "mixins/custom/_navbar.scss";
-
@import "custom/_grid.scss";
@import "custom/_type.scss";
@import "custom/_scaffolding.scss";
@@ -26,133 +25,128 @@
@import "custom/_icon.scss";
@import "custom/_category-page.scss";
@import "custom/_product-card.scss";
+@import "custom/_modals.scss";
html {
- height: 100%;
+ height: 100%;
}
body {
- display: flex;
- flex-direction: column;
- height: 100%;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
}
header {
- .navbar-default {
- border-color: $brand-primary;
- border-width: 4px 0 0 0;
- position: relative;
- z-index: 9999;
- }
+ .navbar-default {
+ border-color: $brand-primary;
+ border-width: 4px 0 0 0;
+ position: relative;
+ z-index: 9999;
+ }
}
footer {
- flex: 0 0 auto;
+ flex: 0 0 auto;
}
-#all-products-popover + .popover {
- width: 480px;
+#all-products-popover+.popover {
+ width: 480px;
}
-#bulk-order-popover + .popover {
- width: 305px;
+#bulk-order-popover+.popover {
+ width: 305px;
}
main {
- padding-top: $navbar-margin-bottom;
- position: relative;
- flex: 1 0 auto;
-
- @media (max-width: $screen-sm-max) {
- .navbar-fixed-top + .navbar-fixed-top + & {
- margin-top: ($navbar-height + 1px) * 2 + $navbar-margin-bottom; // 1px border
- }
-
- .navbar-fixed-top + .navbar-fixed-top + .navbar-fixed-top:not(.ng-hide) + & {
- margin-top: ($navbar-height + 1px) * 3 + $navbar-margin-bottom; // 1px border
+ padding-top: $navbar-margin-bottom;
+ position: relative;
+ flex: 1 0 auto;
+ @media (max-width: $screen-sm-max) {
+ .navbar-fixed-top + .navbar-fixed-top + & {
+ margin-top: ($navbar-height + 1px) * 2 + $navbar-margin-bottom; // 1px border
+ }
+ .navbar-fixed-top+.navbar-fixed-top+.navbar-fixed-top:not(.ng-hide)+& {
+ margin-top: ($navbar-height + 1px) * 3 + $navbar-margin-bottom; // 1px border
+ }
}
- }
-
- padding-bottom: $navbar-margin-top;
+ padding-bottom: $navbar-margin-top;
}
.mobile-app {
- width: 120px;
+ width: 120px;
}
.btn-youtube {
- @include btn-social(#e52d27);
+ @include btn-social(#e52d27);
}
.ng-submitted input.ng-invalid.ng-invalid-required,
.ng-submitted input.ng-invalid.ng-invalid-email,
-.ng-submitted input.ng-invalid.ng-invalid-pattern {
- border-color: #883333;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+.ng-submitted input.ng-invalid.ng-invalid-pattern {
+ border-color: #883333;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.btn-marging-right {
- margin-right: 13px;
+ margin-right: 13px;
}
-
//Dashboard
-
.arrow-padding-left {
- padding-left: 10px;
+ padding-left: 10px;
}
.spend-report-body {
- display: flex;
- justify-content: space-around;
- align-items: center;
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
}
.spend-report-card {
- display: flex;
- flex-direction: column;
+ display: flex;
+ flex-direction: column;
}
.user-roles-card {
- display: flex;
- align-items: flex-start;
- margin-bottom: 10px;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 10px;
}
.user-roles-card-body {
- display: flex;
- flex-direction: column;
- margin-left: 10px;
- font-family: $font-family-sans-serif;
- .title {
- line-height: $line-height-base;
- }
- .description {
- color: $gray-roles-description;
- font-size: $font-size-small;
- }
+ display: flex;
+ flex-direction: column;
+ margin-left: 10px;
+ font-family: $font-family-sans-serif;
+ .title {
+ line-height: $line-height-base;
+ }
+ .description {
+ color: $gray-roles-description;
+ font-size: $font-size-small;
+ }
}
.no-permission {
- background: url('../../images/dashboard-placeholder-bg.png') right no-repeat;
- padding: 60px;
- display: flex;
- align-items: center;
+ background: url('../../images/dashboard-placeholder-bg.png') right no-repeat;
+ padding: 60px;
+ display: flex;
+ align-items: center;
.message {
- width: 179px;
- margin-left: 35px;
- font-family: $font-family-sans-serif;
- color: $gray-no-permission;
- font-weight: bold;
+ width: 179px;
+ margin-left: 35px;
+ font-family: $font-family-sans-serif;
+ color: $gray-no-permission;
+ font-weight: bold;
}
}
.user-inactive {
- color: $gray-user-inactive;
+ color: $gray-user-inactive;
}
-
.modal-flex-footer {
display: flex;
padding: 15px;
@@ -172,26 +166,24 @@ main {
justify-content: space-between;
padding-top: 10px;
padding-bottom: 10px;
-
button.close {
font-size: 35px;
}
-
- &:before, &:after {
+ &:before,
+ &:after {
display: none;
}
}
// Index page
-
.credentials-block {
display: flex;
justify-content: space-around;
align-items: center;
font-family: $font-family-sans-serif;
.credentials-block-text {
- font-size: $font-size-small;
- margin-left: 14px;
+ font-size: $font-size-base;
+ margin-left: 14px;
}
.credentials-block-link {
font-weight: bold;
@@ -204,6 +196,16 @@ main {
background-color: $gray-striped-table;
}
+// Add to cart modal
+
+.add-cart-item-total {
+ height: 40px;
+}
+
+.dialog-data-item:not(:last-child), .order-line-item:not(:last-child) {
+ border-bottom: 1px solid $gray-lighter;
+}
+
// Totals block
.fee-margin-bottom {
diff --git a/assets/scss/_helpers.scss b/assets/scss/_helpers.scss
index 180d827c..21db4437 100644
--- a/assets/scss/_helpers.scss
+++ b/assets/scss/_helpers.scss
@@ -17,3 +17,7 @@
vertical-align: middle;
float: none;
}
+
+.opacity-100 {
+ opacity: 1;
+}
diff --git a/assets/scss/custom/_forms.scss b/assets/scss/custom/_forms.scss
index 8bebb816..ba0a0542 100644
--- a/assets/scss/custom/_forms.scss
+++ b/assets/scss/custom/_forms.scss
@@ -1,4 +1,18 @@
-.form-inline {
+// Remove arrows/spinners from input with type="number"
+
+/* Chrome, Safari, Edge, Opera */
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+/* Firefox */
+input[type='number'] {
+ -moz-appearance: textfield;
+}
+
+.form-inline {
.form-group + .form-group {
margin-left: $form-group-margin-left;
}
diff --git a/assets/scss/custom/_modals.scss b/assets/scss/custom/_modals.scss
index e69de29b..b4be5594 100644
--- a/assets/scss/custom/_modals.scss
+++ b/assets/scss/custom/_modals.scss
@@ -0,0 +1,6 @@
+// Prevent pseudo-elements from impacting the flex calculation
+
+.modal-footer:after,
+.modal-footer:before {
+ display: none;
+}
diff --git a/assets/scss/custom/_tables.scss b/assets/scss/custom/_tables.scss
index 0c453501..c878c67f 100644
--- a/assets/scss/custom/_tables.scss
+++ b/assets/scss/custom/_tables.scss
@@ -50,6 +50,9 @@
.table > tbody > tr > td {
border-right: 1px solid $gray-lighter;
border-top: 0;
+ font-family: $font-family-sans-serif;
+ font-size: 14px;
+ padding: 8px 8px 8px 12px;
}
.table > tbody > tr > td.no-border {
@@ -65,6 +68,11 @@
font-weight: bold;
font-size: 14px;
line-height: 20px;
+ padding: 14px 8px 14px 10px;
+}
+
+.table > tbody + tbody {
+ border-top: 1px solid $gray-lighter;
}
.table.no-vertical-borders {
@@ -79,19 +87,10 @@
cursor: pointer;
}
-.table > tbody > tr > td > .ng-binding {
- font-family: $font-family-sans-serif;
- font-size: 14px;
-}
-
.orders-list-table tr td {
width: 16.6%;
}
-.table > thead > tr > th {
- padding: 14px 8px 14px 10px;
-}
-
.table.small-table-head {
> thead > tr > th {
padding-top: 7px;
@@ -110,10 +109,6 @@
}
}
-.table > tbody > tr > td {
- padding: 8px 8px 8px 12px;
-}
-
.table > tbody > tr:last-child {
border-bottom: 0;
}
@@ -160,7 +155,7 @@ th {
background-color: $body-bg;
}
-.template-product .table > tbody > tr {
+.template-product .table-striped > tbody > tr:nth-of-type(even) {
background-color: $gray-striped-table;
}
diff --git a/assets/scss/custom/_type.scss b/assets/scss/custom/_type.scss
index e8627d19..6af3c58c 100644
--- a/assets/scss/custom/_type.scss
+++ b/assets/scss/custom/_type.scss
@@ -66,6 +66,8 @@ p.product-count {
@include text-emphasis-variant('.text-contrast', $text-contrast);
+@include text-emphasis-variant('.text-muted-contrast', $text-muted-contrast);
+
.text-serif {
font-family: $font-family-serif !important;
}
diff --git a/assets/scss/modules/_loader.scss b/assets/scss/modules/_loader.scss
index 3b2a4794..12ab3b0e 100644
--- a/assets/scss/modules/_loader.scss
+++ b/assets/scss/modules/_loader.scss
@@ -2,7 +2,7 @@
background: rgba(0,0,0,.5);
bottom: 0;
left: 0;
- position: absolute;
+ position: fixed;
right: 0;
top: 0;
z-index: 5000;
diff --git a/locales/en.default.json b/locales/en.default.json
index 3aae9f5a..38c6631e 100644
--- a/locales/en.default.json
+++ b/locales/en.default.json
@@ -253,7 +253,11 @@
"product_search_empty": "No products found",
"product_search_progress": "Searching...",
"categories": "Categories",
- "products": "Products"
+ "products": "Products",
+ "limited_qty": "Limited product quantity",
+ "in_stock": "in stock",
+ "cancel": "Cancel",
+ "confirm": "Confirm"
},
"send_to_email": {
"title": "Select persons to send the email",
diff --git a/package.json b/package.json
index afe355b1..0a153a21 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "version": "1.2.0",
+ "version": "1.3.0",
"name": "vc-demo-theme-b2b",
"author": "VirtoCommerce",
"description": "B2B theme for Storefront",
diff --git a/snippets/dialogs/recently-added-cart-item.liquid b/snippets/dialogs/recently-added-cart-item.liquid
index e1f385e3..fb5003e4 100644
--- a/snippets/dialogs/recently-added-cart-item.liquid
+++ b/snippets/dialogs/recently-added-cart-item.liquid
@@ -1,57 +1,76 @@
diff --git a/snippets/product/grid-item.liquid b/snippets/product/grid-item.liquid
index d5772590..24504e56 100644
--- a/snippets/product/grid-item.liquid
+++ b/snippets/product/grid-item.liquid
@@ -15,7 +15,7 @@
{% assign unavailable = true %}
{% endif %}
-
+
{% include 'shared/item-response-group' %}
{% include 'product/item/image' %}
{% include 'product/compare' %}
diff --git a/templates/cart.liquid b/templates/cart.liquid
index fb29c6ad..d3fb3c25 100644
--- a/templates/cart.liquid
+++ b/templates/cart.liquid
@@ -63,10 +63,10 @@
-
-
+
+
-
+
@@ -287,10 +287,10 @@
MY PRODUCTS
-
-
+
+
-
@@ -374,6 +374,7 @@