'use strict'; /* US - App Module */ var app = angular.module('tastingNotesApp', [ 'wineCellarConstants', 'wineCellarControllers', 'wineCellarDirectives', 'wineCellarFilters', 'utilServices', 'apiServices', // 'apiBvServices', 'ui.router', 'ngResource', 'ngSanitize', 'ngAnimate', 'ui.bootstrap.pagination', 'ui.bootstrap.tooltip', 'ui.bootstrap.position', 'ui.bootstrap.bindHtml', 'ui.bootstrap.popover', 'slick' ]); app.config([ '$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { // For any unmatched url, redirect to / $urlRouterProvider.otherwise('/'); // Now set up the states $stateProvider.state('notes', { url: '/', templateUrl: '/assets/views/us/cellar/wine_grid_notes.html', controller: 'notesController' }); } ]); if (!cellarOverrides) { var cellarOverrides = {}; } // Hack for AU (avoid DataLayer Errors) if (!dataLayer) { var dataLayer = []; } var wineCellarControllers = angular.module('wineCellarControllers', []); wineCellarControllers.controller('notesController', [ '$scope', '$rootScope', 'api', '$resource', 'util', '$window', '$location', function($scope, $rootScope, api, $resource, util, bv_config, $window, $location) { $scope.brand = util.brand(); $scope.brandTag = util.brandInfo($scope.brand).shorthand; $scope.brandBtn = 'btn btn-primary'; $scope.defaultBtn = 'btn btn-default'; $scope.brandURL = util.domain(); var environment = util.env(); var country = util.country(); $scope.items = []; $scope.dataReady = false; $scope.dataEmpty = false; $scope.loadingStatusMessage = true; $scope.loadingErrorMessage = false; $scope.loading = true; $scope.orderProp = '-userItemDetails.lastUpdatedDate'; // Load Ratings from API - Attach data to view $scope.getTastingNotes = function() { api.notes .list( {brand: $scope.brandTag}, function() { // console.log('success'); }, function(errorResult) { // console.log('error', errorResult); if (errorResult.status === 405 || errorResult.status === 500 || errorResult.status === 404) { //console.log('500 - 405 error'); } } ) .$promise.then(function(data) { $scope.tastingNotesData = data; $scope.mergeData(data); }); }; $scope.mergeData = function(notes) { api.purchases .list( {}, function(successResult) { // console.log('data loaded.'); }, function(errorResult) { // console.log('error', errorResult); if (errorResult.status === 405 || errorResult.status === 500 || errorResult.status === 404) { //console.log('500 - 405 error'); } } ) .$promise.then(function(data) { $scope.items = []; var notesData = notes; var purchaseData = data.response.userItems; _.each(purchaseData, function(value) { var existing = _.filter(notesData, function(obj) { return obj.itemCode == value.product.itemCode; }); if (existing.length) { value.filename = existing[0].filepath; value.notes = true; value.color = value.product.colourId; $scope.items.push(value); } else { value.notes = false; value.color = value.product.colourId; $scope.items.push(value); } }); $scope.items = _.filter($scope.items, function(obj) { return obj.notes == true; }); if ($scope.items.length) { $scope.dataReady = true; $scope.dataEmpty = false; $scope.loading = false; $scope.loadingStatusMessage = false; $scope.setPagination(); } else { $scope.dataEmpty = true; $scope.loading = false; $scope.loadingStatusMessage = false; } }); }; $scope.searchNote = function(filterText) { //console.log('filterText', filterText); dataLayer.push({ event: 'GAevent', eventCategory: 'Wine Club Management', eventAction: 'My Tasting Notes', eventLabel: 'Search ' + filterText }); }; $scope.gaSort = function(orderProp) { //console.log('orderProp', orderProp); dataLayer.push({ event: 'GAevent', eventCategory: 'Wine Club Management', eventAction: 'My Tasting Notes', eventLabel: 'Sort ' + orderProp }); }; $scope.viewNote = function() { dataLayer.push({ event: 'GAevent', eventCategory: 'Wine Club Management', eventAction: 'My Tasting Notes', eventLabel: 'View Tasting Note' }); }; $scope.colorFilter = function($event, filterVal) { dataLayer.push({ event: 'GAevent', eventCategory: 'Wine Club Management', eventAction: 'My Tasting Notes', eventLabel: 'Tab Click - ' + filterVal }); $('ul.nav-tabs li').removeClass('active'); $($event.target) .parent() .toggleClass('active'); $scope.filters.color = filterVal; }; // -------- PAGINATION -------- $scope.setPagination = function() { $scope.currentPage = 1; $scope.maxSize = 15; $scope.perPage = 15; }; $scope.setPage = function(pageNo) { $scope.currentPage = pageNo; }; // -------- INITIAL VARIABLES -------- if (environment === 'www' || environment === 'preview') { $scope.getTastingNotes(); } else { $scope.dataEmpty = true; $scope.loading = false; $scope.loadingStatusMessage = false; } // $scope.getBVConfig(); $scope.filters = {}; $scope.categories = ['Red', 'White', 'Rose', 'Sparkling']; } ]); wineCellarControllers.directive('equalize', function($timeout) { return { restrict: 'A', link: function(scope, element, attr) { scope.setTallest = function() { $timeout(function() { //this coade will execute right after ng-repeat rendering has been completed var tallest = 0, currentElement = angular.element('.wine-grid-container'); // Loop through each element angular.forEach(angular.element('.wine-grid-container'), function(value, key) { var thisHeight = angular.element(value).height(); if (thisHeight > tallest) { tallest = thisHeight; } }); // Apply height to all elements currentElement.height(tallest); }, 200); }; if (scope.$last === true) { scope.setTallest(); } scope.$watch('items', function(oldVal, newVal) { if (newVal.length) { scope.setTallest(); } }); } }; }); /* ==== All functions should be setup as an object literal to help with namespacing / prevent global vars */ 'use strict'; /* App Module */ var wineCellarDirectives = angular.module('wineCellarDirectives', []); wineCellarDirectives.directive('fallbackSrc', function() { return { link: function postLink(scope, iElement, iAttrs) { iElement.bind('error', function() { angular.element(this).attr('src', iAttrs.fallbackSrc); }); } }; }); wineCellarDirectives.directive('flashNotification', function($animate, $timeout) { return { restrict: 'E', scope: {}, link: function postLink(scope, iElement, iAttrs) { scope.$on('flashNotification::message', function(e, message) { var messageElement = angular.element('
'); messageElement.text(message); iElement.append(messageElement); $timeout(function() { $animate.leave(messageElement); }, 1500); // Can customise time }); } }; }); wineCellarDirectives.directive('cartNotification', function($animate, $timeout) { return { restrict: 'E', scope: {}, link: function postLink(scope, iElement, iAttrs) { scope.$on('cartNotification::message', function(e, message) { var messageElement = angular.element(''); messageElement.text(message); iElement.append(messageElement); $timeout(function() { $animate.leave(messageElement); }, 2500); // Can customise time }); } }; }); wineCellarDirectives.directive('starRating', function() { return { restrict: 'A', template: '', scope: { ratingValue: '=' }, link: function(scope, elem, attrs) { scope.Ulclasses = ''; scope.liclasses = ''; if (pageLayer[0].brand === 'vws' || pageLayer[0].country === 'tw' || pageLayer[0].country === 'hk') { scope.Ulclasses = ' d-flex justify-content-start align-items-center'; scope.liclasses = ' mr-7'; } scope.stars = []; for (var i = 0; i < scope.ratingValue; i++) { scope.stars.push({}); } } }; }); wineCellarDirectives.directive('starRatingHover', function() { return { restrict: 'A', template: '', scope: { ratingValue: '=' }, link: function(scope, elem, attrs) { scope.stars = []; for (var i = 0; i < scope.ratingValue; i++) { scope.stars.push({}); } } }; }); wineCellarDirectives.directive('avgStarRating', function() { return { restrict: 'A', template: '', scope: { ratingValue: '=' }, link: function(scope, elem, attrs) { var updateStars = function(value) { scope.stars = []; var ratingDecimal = (value % 1).toFixed(1); var ratingWhole = Math.floor(value); for (var i = 0; i <= 4; i++) { if (i <= ratingWhole - 1) { scope.starClass = 'fa fa-star'; } else if (ratingDecimal >= 0.5) { scope.starClass = 'fa fa-star fa-star-half-full'; ratingDecimal = 0.0; } else { scope.starClass = 'fa fa-star fa-star-o'; } scope.stars.push({ starClass: scope.starClass }); } }; scope.$watch('ratingValue', function(newVal, oldVal) { if (newVal) { updateStars(newVal); } }); } }; }); wineCellarDirectives.directive('toggleFavorites', function() { return { scope: true, restrict: 'E', replace: true, template: '', link: function(scope, element, attrs) { element.bind('click', function() { element.toggleClass('fa-heart-o'); }); } }; }); wineCellarDirectives.directive('toggleDislike', function() { return { scope: true, restrict: 'E', replace: true, template: '', link: function(scope, element, attrs) { element.bind('click', function() { element.toggleClass('fa-ban-active'); }); } }; }); wineCellarDirectives.directive('favorites', function() { return { template: '', scope: { userFavorite: '=enabled', userDislike: '=disabled', likeClass: '=', favClass: '=' }, restrict: 'E', controller: function($scope) { $scope.toggle = function() { $scope.userFavorite = !$scope.userFavorite; $scope.initFavorite = false; if ($scope.userFavorite === false) { $scope.favClass = 'fa fa-heart-o'; $scope.userDislike = false; } else if ($scope.userFavorite === true) { $scope.favClass = 'fa fa-heart'; $scope.likeClass = 'fa fa-thumbs-o-down'; $scope.userDislike = false; } }; } }; }); wineCellarDirectives.directive('dislikes', function() { return { template: '', scope: { userFavorite: '=disabled', userDislike: '=enabled', likeClass: '=', favClass: '=' }, restrict: 'E', controller: function($scope) { $scope.toggle = function() { $scope.userDislike = !$scope.userDislike; $scope.initDislike = !$scope.initDislike; if ($scope.userDislike === false) { $scope.likeClass = 'fa fa-thumbs-o-down'; $scope.userFavorite = false; } else if ($scope.userDislike === true) { $scope.likeClass = 'fa fa-thumbs-down'; $scope.favClass = 'fa fa-heart-o'; $scope.userFavorite = false; } }; } }; }); wineCellarDirectives.directive('starsRating', function() { return { restrict: 'A', template: '', scope: { ratingValue: '=', max: '=', onRatingSelected: '&', clickValue: '=', ratingRequired: '=' }, link: function(scope, elem, attrs) { var updateStars = function() { scope.stars = []; for (var i = 0; i < scope.max; i++) { scope.stars.push({ filled: i < scope.ratingValue }); switch (scope.ratingValue) { case 1: scope.ratingValueTxt = 'Poor'; break; case 2: scope.ratingValueTxt = 'Fair'; break; case 3: scope.ratingValueTxt = 'Average'; break; case 4: scope.ratingValueTxt = 'Good'; break; case 5: scope.ratingValueTxt = 'Excellent'; break; default: scope.ratingValueTxt = ''; break; } } }; //Click Stars scope.toggle = function(index) { scope.ratingValue = index + 1; scope.onRatingSelected({ rating: index + 1 }); scope.clickValue = scope.ratingValue; }; //Hover Stars scope.fillStars = function(index) { scope.ratingValue = index + 1; scope.onRatingSelected({ rating: index + 1 }); }; //Mouse Leave Goes Back To Clicked Star scope.emptyStars = function(index) { scope.ratingValue = scope.clickValue; }; scope.starClass = function(/** Star */ star, /** Integer */ idx) { var starClass = 'fa-star-o'; if (star.filled) { starClass = 'fa-star'; } return starClass; }; scope.$watch('ratingValue', function(oldVal, newVal) { if (newVal) { scope.ratingRequired = false; updateStars(); } }); } }; }); wineCellarDirectives.directive('paginationViewResults', function() { return { restrict: 'E', template: '(Viewing {{firstRec}} - {{lastRec}} of {{totalResults}} Wines)', replace: true, scope: { perPage: '=', totalItems: '=', currentPage: '=' }, link: function(scope, elem, attrs) { scope.setResults = function(page) { var totalPerPage = scope.perPage * page; scope.firstRec = scope.perPage * page - scope.perPage + 1; scope.lastRec = totalPerPage > scope.totalResults ? scope.totalResults : totalPerPage; }; scope.$watch('totalItems', function(newVal, oldVal) { if (newVal) { scope.totalResults = newVal; scope.setResults(scope.currentPage); } }); scope.$watch('currentPage', function(newVal, oldVal) { if (newVal) { scope.setResults(newVal); } }); } }; }); //Control label next to the total wines value wineCellarDirectives.directive('totalWineLabel', function() { return { restrict: 'E', template: '{{wineTxtLabel}}', replace: true, scope: { totalItems: '=' }, link: function(scope) { /* Check if the total number of items changed if it doesn't update label */ scope.$watch('totalItems', function(newVal) { if (newVal) { if (newVal === 1) { scope.wineTxtLabel = 'wine'; } else { scope.wineTxtLabel = 'wines'; } } }); } }; }); 'use strict'; /* App Module */ var wineCellarFilters = angular.module('wineCellarFilters', []); wineCellarFilters.filter('favorite', function() { return function(input) { return input ? 'fa-heart' : 'fa-heart-o'; }; }); wineCellarFilters.filter('notes', function() { return function(input) { return input ? 'fa-pencil-square-o' : 'fa-pencil-square-o'; }; }); wineCellarFilters.filter('offset', function() { return function(input, start) { start = parseInt(start, 10); return input.slice(start); }; }); wineCellarFilters.filter('truncate', function() { return function(text, length, end) { if (isNaN(length)) length = 10; if (end === undefined) end = '...'; if (text.length <= length || text.length - end.length <= length) { return text; } else { return String(text).substring(0, length - end.length) + end; } }; }); wineCellarFilters.filter('startFrom', function() { return function(input, start) { start = +start; //parse to int return input.slice(start); }; }); 'use strict'; var apiServices = angular.module('apiServices', []); apiServices.factory('api', function($resource) { return { cartUS: $resource( '/api/cart/:action/:itemcode/:item/:qty?method=:method', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, add: {method: 'PUT', params: {item: '@item', qty: '@qty', itemcode: 'itemcode'}}, update: {method: 'PUT', params: {item: '@item', qty: '@qty', method: 'set', itemcode: 'itemcode'}}, remove: {method: 'DELETE', params: {item: '@item', itemcode: 'itemcode'}}, del: {method: 'PUT', params: {action: 'delete', item: '@item', itemcode: 'itemcode'}} } ), cartLWM: $resource( '/api/cart/:action/:salescode/:item/:qty', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, add: {method: 'PUT', params: {item: '@item', qty: '@qty', salescode: 'salescode'}}, remove: {method: 'DELETE', params: {item: '@item', salescode: 'salescode'}}, del: {method: 'PUT', params: {action: 'delete', item: '@item', salescode: 'itemcode'}} } ), cartUK: $resource( '/api/cart/:action/:itemcode/:item/:qty', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, add: {method: 'PUT', params: {item: '@item', qty: '@qty', itemcode: 'itemcode'}}, remove: {method: 'DELETE', params: {item: '@item', itemcode: 'itemcode'}}, del: {method: 'PUT', params: {action: 'delete', item: '@item', itemcode: 'itemcode'}} } ), cartBatch: $resource( '/api/cart/:action/itemcode', {}, { add: {method: 'POST'} } ), cellar: $resource( '/api/user/:list/:action/:item', {}, { list: {method: 'GET', params: {list: '@list', action: 'list'}, isArray: false}, save: {method: 'PUT', params: {list: '@list', item: '@item'}}, remove: {method: 'DELETE', params: {list: '@list', item: '@item'}}, del: {method: 'PUT', params: {list: '@list', action: 'delete', item: '@item'}} } ), favourites: $resource( '/api/user/favourites/:action/:item', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, save: {method: 'PUT', params: {item: '@item'}}, remove: {method: 'DELETE', params: {item: '@item'}}, del: {method: 'PUT', params: {action: 'delete', item: '@item'}} } ), dislike: $resource( ' /api/user/donotsenditem/:action/:item', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, add: {method: 'PUT', params: {item: '@item'}}, del: {method: 'PUT', params: {action: 'delete', item: '@item'}} } ), purchases: $resource( '/api/user/purchases/:action/', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false} } ), ratings: $resource( '/api/user/ratings/:action/', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false} } ), recommendations: $resource( '/api/user/recommendations/:action/:mixed', {}, { list: {method: 'GET', params: {action: 'list', mixed: '@mixed'}, isArray: false} } ), product: $resource( '/api/product/item/:itemcode', {}, { list: {method: 'GET', params: {itemcode: '@itemcode'}, isArray: false} } ), caseContents: $resource( '/api/product/case/:itemcode', {}, { list: {method: 'GET', params: {itemcode: '@itemcode'}, isArray: false} } ), preferences: $resource( '/api/user/preferences/:action/', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false}, add: {method: 'POST'} } ), alternateItem: $resource( '/api/product/alternateItem/:itemcode', {}, { list: {method: 'GET', params: {itemcode: '@itemcode'}, isArray: false} } ), offerlist: $resource( '/api/itemlist/:name/:locale/:companyCode', {}, { list: {method: 'GET', params: {action: 'list'}, isArray: false} } ), notes: $resource( '/php/us/tasting_notes.php?brand=:brand', {}, { list: {method: 'GET', params: {brand: '@brand'}, isArray: true} } ) }; }); var utilServices = angular.module('utilServices', []); utilServices.factory('util', function() { return { brand: function() { var brand = _.filter( [ 'zagat', 'tcmwineclub', 'natgeowine', 'virgin', 'wsjwine', 'winepeople', 'australian', 'nprwineclub', 'bhgwine', 'macyswinecellar', 'laithwaites', 'sundaytimeswineclub', 'bbcgoodfoodwineclub', 'averys', 'bawineclub', 'bawineflyer', 'bawineexplorer', 'velocity', 'directwines', 'directwinesHK' ], function(elem) { return location.host.indexOf(elem) > 0; } ); if ( brand[0] === 'tcmwineclub' || brand[0] === 'natgeowine' || brand[0] === 'nprwineclub' || brand[0] === 'bhgwine' ) { brand[0] = 'laithwaites'; } return brand[0]; }, brandInfo: function(brand) { var phoneNumber = '1-800-649-4637'; if (this.country() === 'us') { if ( brand === 'laithwaites' || brand === 'tcmwineclub' || brand === 'natgeowine' || brand === 'nprwineclub' || brand === 'bhgwine' ) { brand = 'laithwaites_us'; } } var obj = { wsjwine: { name: 'WSJwine', phone: '1-877-975-9463', shorthand: 'wsj', locale: 'en_US_WSJ' }, laithwaites_us: { name: "Laithwaite's Wine", phone: phoneNumber, shorthand: 'law', locale: 'en_US_4S' }, macyswinecellar: { name: "Macy's Wine Cellar", phone: '1-888-997-0319', shorthand: 'mcy', locale: 'en_US_MACYS' }, virgin: { name: 'Virgin Wines', phone: '1-866-426-0336', shorthand: 'vir', locale: 'en_US_Virgin' }, winepeople: { name: 'Wine People', phone: '1300 362 629', shorthand: 'wpe', locale: 'en_AU_WP' }, australian: { name: 'The Australian Wine', phone: '1300 765 021', shorthand: 'adc', locale: 'en_AU_ADC' }, velocity: { name: 'Virgin Wines Redemption store', phone: '1300 241 080', shorthand: 'vws', locale: 'en_AU_VWS' }, directwines: { name: 'Direct Wines', phone: '(02)7701-0188', shorthand: 'law', locale: 'en_TW_LAW' }, directwinesHK: { name: 'Direct Wines', phone: '8120 3826', shorthand: 'hlw', locale: 'en_HK_LW' }, laithwaites: { name: "Laithwaite's Wine", phone: '03330 148 198', shorthand: 'law', locale: 'en_GB_UKLAIT' }, sundaytimeswineclub: { name: 'Sunday Times Wine Club', phone: '03330 142 776', shorthand: 'stw', locale: 'en_GB_UKCLUB' }, averys: { name: 'Averys of Bristol', phone: '03330 148 208', shorthand: 'avy', locale: 'en_GB_AVR' }, bawineclub: { name: 'The Wine Explorer', phone: '03330 142 757', shorthand: 'ba', locale: 'en_GB_UKLAIT' }, bawineflyer: { name: 'The British Airways Wine Flyer', phone: '03330 142 759', shorthand: 'ba', locale: 'en_GB_UKLAIT' }, bawineexplorer: { name: 'The Wine Explorer', phone: '03330 142 757', shorthand: 'ba', locale: 'en_GB_UKLAIT' }, bbcgoodfoodwineclub: { name: 'BBC Good Food Wine Club', phone: '03330 148 208', shorthand: 'bbc', locale: 'en_GB_UKLAIT' } }; return obj[brand]; }, dataAreaId: function() { var dataAreaId; if (dataLayer && dataLayer[0] && dataLayer[0].dataAreaId === 'LWM') { dataAreaId = 'LWM'; } else { dataAreaId = 'UK'; } return dataAreaId; }, country: function() { if (location.host.indexOf('co.uk') > 0) { return 'uk'; } else if (location.host.indexOf('com.au') > 0) { return 'au'; } else if (location.host.indexOf('co.nz') > 0) { return 'nz'; } else if (location.host.indexOf('com.tw') > 0) { return 'tw'; } else if (location.host.indexOf('com.hk') > 0) { return 'hk'; } else { return 'us'; } }, domain: function() { return location.host; }, env: function() { var full = window.location.host; var parts = full.split('.'); return parts[0]; }, showUnlimited: function() { var freeShipProfile = pageLayer[0].fsp; var offerUnlimited = pageLayer[0].ou; if (offerUnlimited === '1' || offerUnlimited === '') { return 'standard'; } else if (offerUnlimited === '2') { return 'promotional'; } else if (offerUnlimited === '3') { return 'half-price'; } else if (freeShipProfile === 'true' || offerUnlimited === '0') { return false; } }, unlimitedInfo: function(brand, unlimitedType) { var obj = { wsjwine: { unlimited: { standard: '/product/WSJwine-1-Year-Advantage-Delivery-Membership/00034SV', promotional: '/product/WSJwine-1-Year-Unlimited-Delivery-Membership/17110UL', 'half-price': '/product/WSJwine-1-Year-Unlimited-Delivery-Membership/17111UL' } }, laithwaites: { unlimited: { standard: '/product/Laithwaites-1-Year-Unlimited-Delivery-Membership/00033SV', promotional: '/product/Laithwaites-1-Year-Unlimited-Delivery-Membership/17096UL', 'half-price': '/product/Laithwaites-1-Year-Unlimited-Delivery-Membership/17100UL' } }, virgin: { unlimited: { standard: '/product/Virgin-Wines-1-Year-Unlimited-Delivery-Membership/00035SV', promotional: '/product/Virgin-Wines-1-Year-Unlimited-Delivery-Membership/17112UL', 'half-price': '/product/Virgin-Wines-1-Year-Unlimited-Delivery-Membership/17113UL' } }, macyswinecellar: { unlimited: { standard: "/product/Macy's-1-Year-Unlimited-Delivery-Membership/00036SV", promotional: "/product/Macy's-1-Year-Unlimited-Delivery-Membership/18015UL", 'half-price': "/product/Macy's-1-Year-Unlimited-Delivery-Membership/18016UL" } } }; return obj[brand].unlimited[unlimitedType]; }, setGA: function(category, action, label) { dataLayer.push({event: 'GAevent', eventCategory: category, eventAction: action, eventLabel: label}); return {category: category, action: action, label: label}; } }; }); /* Config Module */ var wineCellarConstants = angular.module('wineCellarConstants', []); wineCellarConstants.constant('bv_config', { staging: { au: { winepeople: 'http://winepeople.ugc.bazaarvoice.com/bvstaging/3128-en_au/', virgin: 'http://reviews.virginwines.com.au/bvstaging/2511-en_au/', australian: 'http://australianwine.ugc.bazaarvoice.com/bvstaging/3127-en_au/' }, nz: { laithwaiteswine: 'http://laithwaiteswine.ugc.bazaarvoice.com/bvstaging/3129-en_us/' }, tw: { directwines: '' }, hk: { directwines: '' }, us: { laithwaiteswine: 'http://laithwaiteswine.ugc.bazaarvoice.com/bvstaging/3129-en_us/', virgin: 'http://reviews.virginwines.com/bvstaging/2511/', wsjwine: 'http://reviews.wsjwine.com/bvstaging/3131/' }, uk: { sundaytimeswineclub: '//stwc.ugc.bazaarvoice.com/bvstaging/2131-en_gb/', laithwaites: '//laithwaites.ugc.bazaarvoice.com/bvstaging/3130redes-en_gb/' } }, production: { au: { winepeople: 'http://winepeople.ugc.bazaarvoice.com/3128-en_au/', virgin: 'http://reviews.virginwines.com.au/2511-en_au/', australian: 'http://australianwine.ugc.bazaarvoice.com/3127-en_au/' }, nz: { laithwaiteswine: 'http://laithwaiteswine.ugc.bazaarvoice.com/bvstaging/3129-en_us/' }, tw: { directwines: '' }, hk: { directwines: '' }, us: { laithwaiteswine: 'http://laithwaiteswine.ugc.bazaarvoice.com/3129-en_us/', virgin: 'http://reviews.virginwines.com/2511/', wsjwine: 'http://reviews.wsjwine.com/3131/' }, uk: { sundaytimeswineclub: '//stwc.ugc.bazaarvoice.com/2131-en_gb/64093/', laithwaites: '//laithwaites.ugc.bazaarvoice.com/3130redes-en_gb/' } } }); wineCellarConstants.constant('bv_api_config', { staging: { us: { laithwaiteswine: 'skktf57raycmmd993wj9npgy', virgin: 'hzackg6b2vfcxw49ya58zju5', wsjwine: 'mhm2fyta7p9kf566vj8zpmk3', macyswinecellar: 'caBuMVWgdcOkLSZtRfXig9jJ8ynxaF6s8skNjJGcYLT5I' } }, production: { us: { laithwaiteswine: 'lmzo8bsuy3ia1ubomqcrzrktq', virgin: '3f2z1is5bk9n9iosddcx6pagf', wsjwine: '9m8wfbdu0ss2y8vtdauab5yhs', macyswinecellar: 'caWTd3SjVMMOVTkbh58qo51gTgQMilHu4oE1oePFjQE6s' } } });