@nakedwines/naked-components 1.0.0 → 3.637.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of @nakedwines/naked-components might be problematic. Click here for more details.
- package/README.md +33 -0
- package/build-utils/update-library.js +91 -0
- package/library/globals.js +4 -0
- package/library/index.js +69 -0
- package/package.json +22 -6
- package/src/components/badges/Badge.vue +20 -0
- package/src/components/badges/Badge.vue?1b45 +1 -0
- package/src/components/badges/Badge.vue?5424 +10 -0
- package/src/components/badges/Badge.vue?c5b6 +1 -0
- package/src/components/banners/Banner.vue +20 -0
- package/src/components/banners/Banner.vue?2006 +1 -0
- package/src/components/banners/Banner.vue?36d1 +1 -0
- package/src/components/banners/Banner.vue?9b97 +4 -0
- package/src/components/buttons/Button.vue +21 -0
- package/src/components/buttons/Button.vue?2035 +1 -0
- package/src/components/buttons/Button.vue?5c96 +1 -0
- package/src/components/buttons/Button.vue?838e +26 -0
- package/src/components/buttons/Button.vue?e88c +1 -0
- package/src/components/buttons/LoadingButton.vue +20 -0
- package/src/components/buttons/LoadingButton.vue?2f5e +17 -0
- package/src/components/buttons/LoadingButton.vue?4a65 +1 -0
- package/src/components/buttons/LoadingButton.vue?65be +1 -0
- package/src/components/buttons/Ripple.vue +20 -0
- package/src/components/buttons/Ripple.vue?130a +1 -0
- package/src/components/buttons/Ripple.vue?2026 +13 -0
- package/src/components/buttons/Ripple.vue?4835 +1 -0
- package/src/components/cards/ContentCard.vue +20 -0
- package/src/components/cards/ContentCard.vue?35c8 +10 -0
- package/src/components/cards/ContentCard.vue?7164 +1 -0
- package/src/components/cards/ContentCard.vue?ec15 +1 -0
- package/src/components/cards/bottle-cards/CaseContentsCard.vue +20 -0
- package/src/components/cards/bottle-cards/CaseContentsCard.vue?3ac7 +1 -0
- package/src/components/cards/bottle-cards/CaseContentsCard.vue?7e00 +4 -0
- package/src/components/cards/bottle-cards/CaseContentsCard.vue?dd6f +1 -0
- package/src/components/cards/bottle-cards/CaseProductCard.vue +21 -0
- package/src/components/cards/bottle-cards/CaseProductCard.vue?0cb0 +1 -0
- package/src/components/cards/bottle-cards/CaseProductCard.vue?1bd2 +1 -0
- package/src/components/cards/bottle-cards/CaseProductCard.vue?25e9 +4 -0
- package/src/components/cards/bottle-cards/CaseProductCard.vue?95f9 +1 -0
- package/src/components/cards/bottle-cards/WineBottleCard.vue +21 -0
- package/src/components/cards/bottle-cards/WineBottleCard.vue?61a8 +1 -0
- package/src/components/cards/bottle-cards/WineBottleCard.vue?7e9a +1 -0
- package/src/components/cards/bottle-cards/WineBottleCard.vue?bd3e +4 -0
- package/src/components/cards/bottle-cards/WineBottleCard.vue?bdcc +1 -0
- package/src/components/cards/bottle-cards/components/BiaText.vue +20 -0
- package/src/components/cards/bottle-cards/components/BiaText.vue?123e +1 -0
- package/src/components/cards/bottle-cards/components/BiaText.vue?3e10 +1 -0
- package/src/components/cards/bottle-cards/components/BiaText.vue?d135 +4 -0
- package/src/components/cards/bottle-cards/components/HeartRatingPanel.vue +20 -0
- package/src/components/cards/bottle-cards/components/HeartRatingPanel.vue?712f +4 -0
- package/src/components/cards/bottle-cards/components/HeartRatingPanel.vue?c55a +1 -0
- package/src/components/cards/bottle-cards/components/HeartRatingPanel.vue?ee3b +1 -0
- package/src/components/cards/bottle-cards/components/PriceBreakdownPanel.vue +20 -0
- package/src/components/cards/bottle-cards/components/PriceBreakdownPanel.vue?5052 +1 -0
- package/src/components/cards/bottle-cards/components/PriceBreakdownPanel.vue?5838 +4 -0
- package/src/components/cards/bottle-cards/components/PriceBreakdownPanel.vue?7aad +1 -0
- package/src/components/cards/bottle-cards/components/WineDetailPanel.vue +20 -0
- package/src/components/cards/bottle-cards/components/WineDetailPanel.vue?5047 +1 -0
- package/src/components/cards/bottle-cards/components/WineDetailPanel.vue?8e3b +1 -0
- package/src/components/cards/bottle-cards/components/WineDetailPanel.vue?d1ea +4 -0
- package/src/components/carousel/Carousel.vue +21 -0
- package/src/components/carousel/Carousel.vue?492f +1 -0
- package/src/components/carousel/Carousel.vue?4e80 +4 -0
- package/src/components/carousel/Carousel.vue?66a0 +1 -0
- package/src/components/carousel/Carousel.vue?72ce +1 -0
- package/src/components/chips/Chip.vue +20 -0
- package/src/components/chips/Chip.vue?7e2c +1 -0
- package/src/components/chips/Chip.vue?9563 +4 -0
- package/src/components/chips/Chip.vue?f42c +1 -0
- package/src/components/footers/sticky-footer/StickyFooter.vue +20 -0
- package/src/components/footers/sticky-footer/StickyFooter.vue?10bf +4 -0
- package/src/components/footers/sticky-footer/StickyFooter.vue?b195 +1 -0
- package/src/components/footers/sticky-footer/StickyFooter.vue?e2d9 +1 -0
- package/src/components/forms/CheckboxInput.vue +20 -0
- package/src/components/forms/CheckboxInput.vue?1713 +1 -0
- package/src/components/forms/CheckboxInput.vue?51c9 +1 -0
- package/src/components/forms/CheckboxInput.vue?feea +4 -0
- package/src/components/forms/QuantityInput.vue +20 -0
- package/src/components/forms/QuantityInput.vue?233a +25 -0
- package/src/components/forms/QuantityInput.vue?4975 +1 -0
- package/src/components/forms/QuantityInput.vue?bb30 +1 -0
- package/src/components/forms/SelectInput.vue +172 -0
- package/src/components/forms/SelectInput.vue?1d47 +1 -0
- package/src/components/forms/SelectInput.vue?642a +21 -0
- package/src/components/forms/SelectInput.vue?7590 +20 -0
- package/src/components/forms/SelectInput.vue?f210 +1 -0
- package/src/components/forms/SelectInput.vue?fc78 +1 -0
- package/src/components/icons/CustomisableHeart.vue +19 -0
- package/src/components/icons/CustomisableHeart.vue?30ab +1 -0
- package/src/components/icons/CustomisableHeart.vue?ce76 +4 -0
- package/src/components/icons/Icon.vue +21 -0
- package/src/components/icons/Icon.vue?47ee +9 -0
- package/src/components/icons/Icon.vue?6e26 +1 -0
- package/src/components/icons/Icon.vue?897e +1 -0
- package/src/components/icons/Icon.vue?e753 +1 -0
- package/src/components/modal/ProductDetailModal.vue +20 -0
- package/src/components/modal/ProductDetailModal.vue?5d3a +1 -0
- package/src/components/modal/ProductDetailModal.vue?9f0f +1 -0
- package/src/components/modal/ProductDetailModal.vue?a2a9 +4 -0
- package/src/components/popover/Popover.vue +20 -0
- package/src/components/popover/Popover.vue?088e +1 -0
- package/src/components/popover/Popover.vue?4dad +1 -0
- package/src/components/popover/Popover.vue?7034 +7 -0
- package/src/components/roundels/Roundel.vue +20 -0
- package/src/components/roundels/Roundel.vue?14bf +7 -0
- package/src/components/roundels/Roundel.vue?a97a +1 -0
- package/src/components/roundels/Roundel.vue?aa28 +1 -0
- package/src/components/shelf/Shelf.vue +20 -0
- package/src/components/shelf/Shelf.vue?50f3 +1 -0
- package/src/components/shelf/Shelf.vue?9eba +1 -0
- package/src/components/shelf/Shelf.vue?d8e7 +4 -0
- package/src/globals/assortments.js +80 -0
- package/src/globals/csrf.js +25 -0
- package/src/globals/functions.js +166 -0
- package/src/globals/products.js +251 -0
- package/src/globals/responsive.js +53 -0
- package/src/globals/validation.js +8 -0
- package/src/globals/variables.js +48 -0
- package/src/mixins/productCard.js +151 -0
- package/src/styles/js-modules/breakpoints.scss +2 -0
- package/index.js +0 -0
@@ -0,0 +1,251 @@
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
2
|
+
|
3
|
+
import { csrf } from './csrf';
|
4
|
+
import { Assortments } from './assortments';
|
5
|
+
import { Logger } from './functions';
|
6
|
+
import { styleNamesIds, styleColours } from './variables';
|
7
|
+
import 'whatwg-fetch';
|
8
|
+
|
9
|
+
export const Products = {
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Fetches a list of products
|
13
|
+
* @param {Array} productIds the list of product IDs
|
14
|
+
* @returns {Array} returns an array of products
|
15
|
+
*/
|
16
|
+
getProductsById({ productIds }) {
|
17
|
+
return new Promise((resolve, reject) => {
|
18
|
+
if (!productIds) {
|
19
|
+
reject({ error: 'productId is required' });
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
|
23
|
+
fetch(`/products?productIds=${productIds}`, {
|
24
|
+
'method': 'GET'
|
25
|
+
}).then(response => {
|
26
|
+
return resolve(response.json());
|
27
|
+
}).catch(error => reject({ error: error }));
|
28
|
+
});
|
29
|
+
},
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Adds a product to basket
|
33
|
+
* @param {Array} productId the product ID to add to basket
|
34
|
+
* @param {Number} quantity quantity to add to basket
|
35
|
+
* @returns {Object} returns a success/error response
|
36
|
+
*/
|
37
|
+
addToBasket({ productId, quantity = 1 }) {
|
38
|
+
return new Promise((resolve, reject) => {
|
39
|
+
if (!productId) {
|
40
|
+
reject({ error: 'productId is required' });
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
|
44
|
+
const headers = new Headers(csrf.header);
|
45
|
+
const formData = new FormData();
|
46
|
+
formData.append('productId', productId.toString());
|
47
|
+
formData.append('quantity', quantity.toString());
|
48
|
+
|
49
|
+
fetch('/customer/add-to-cart.json', {
|
50
|
+
'method': 'POST',
|
51
|
+
'headers': headers,
|
52
|
+
'body': formData
|
53
|
+
}).then(response => {
|
54
|
+
return resolve(response.json());
|
55
|
+
}).catch(error => reject({ error: error }));
|
56
|
+
});
|
57
|
+
},
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Displays an add to basket notification in the header
|
61
|
+
* @param {String} productName the product name to display
|
62
|
+
*/
|
63
|
+
showATBConfirmation(productName) {
|
64
|
+
if (window && window.Notify && window.Notify.CoinPurse) {
|
65
|
+
const config = {
|
66
|
+
settings: { purseType: 'product-added' },
|
67
|
+
productName: productName,
|
68
|
+
autoDismiss: true,
|
69
|
+
timeout: 4000
|
70
|
+
};
|
71
|
+
|
72
|
+
window.Notify.CoinPurse.show(config.settings, config.productName, config.autoDismiss, config.timeout);
|
73
|
+
|
74
|
+
if (window.nkd && window.nkd.headerCart) {
|
75
|
+
window.nkd.headerCart.reload();
|
76
|
+
}
|
77
|
+
}
|
78
|
+
},
|
79
|
+
|
80
|
+
_parseProduct(data) {
|
81
|
+
let model = null;
|
82
|
+
let type;
|
83
|
+
let imageAssortmentKey;
|
84
|
+
let imageMediumCutout = 'mediumCutout';
|
85
|
+
|
86
|
+
// skip item if it's not in the right format
|
87
|
+
if (!data || !data.object) { Logger.log('_parseProduct skipping item', "'object' property not found"); return null; }
|
88
|
+
|
89
|
+
// wrap in try catch so we can skip an item if the data is inconsistent
|
90
|
+
try {
|
91
|
+
// use different keys if it's a case rather than a single product
|
92
|
+
if (data && data.object && data.object.productTypeDesc && data.object.productTypeDesc == 'Case') {
|
93
|
+
type = 'case-product';
|
94
|
+
imageAssortmentKey = 'headline';
|
95
|
+
} else {
|
96
|
+
type = 'single-product';
|
97
|
+
imageAssortmentKey = 'background';
|
98
|
+
}
|
99
|
+
|
100
|
+
model = {
|
101
|
+
id: data.object.id,
|
102
|
+
type: type,
|
103
|
+
data: {
|
104
|
+
id: data.object.id,
|
105
|
+
heading: data.object.productName,
|
106
|
+
subHeading: null,
|
107
|
+
thumbnail: '/merchandising/content/wines/default-content/background.jpg',
|
108
|
+
button: null,
|
109
|
+
pricesCurrent: {
|
110
|
+
prices: {}
|
111
|
+
},
|
112
|
+
positiveRatingPercentage: null,
|
113
|
+
numberOfRatings: null,
|
114
|
+
angelOnly: data.object.angelOnly,
|
115
|
+
tickpoints: null,
|
116
|
+
tickpointsCase: null,
|
117
|
+
taste: null,
|
118
|
+
originForSpiritsOrBeer: data.object.originForSpiritsOrBeer,
|
119
|
+
style: {},
|
120
|
+
percentageMatch: null,
|
121
|
+
likeThis: null,
|
122
|
+
producer: {},
|
123
|
+
url: null,
|
124
|
+
productTypeDesc: null,
|
125
|
+
productQuantity: null,
|
126
|
+
scheme: {},
|
127
|
+
assortmentObjects: {},
|
128
|
+
origin: '',
|
129
|
+
wineGrape: '',
|
130
|
+
hideFromView: false,
|
131
|
+
hideRatings: false,
|
132
|
+
specialDelivery: false,
|
133
|
+
freeShipping: false,
|
134
|
+
bia: {},
|
135
|
+
vegan: false,
|
136
|
+
vegetarian: false,
|
137
|
+
alcoholStrength: null,
|
138
|
+
bottleSizeDesc: '',
|
139
|
+
promotionalPrice: null,
|
140
|
+
angelPrices: false
|
141
|
+
}
|
142
|
+
};
|
143
|
+
// attach ratings
|
144
|
+
if (data.object.hasOwnProperty('ratingData')) {
|
145
|
+
model.data.positiveRatingPercentage = data.object.ratingData.positiveRatingPercentage;
|
146
|
+
model.data.numberOfRatings = data.object.ratingData.numberOfRatings;
|
147
|
+
model.data.hideRatings = data.object.ratingData.hideRatings;
|
148
|
+
}
|
149
|
+
// attach pricing
|
150
|
+
if (data.object.pricesCurrent && data.object.pricesCurrent.prices) {
|
151
|
+
model.data.pricesCurrent.prices = data.object.pricesCurrent.prices;
|
152
|
+
// attach ATB button (customer price)
|
153
|
+
if (data.object.pricesCurrent.prices.customerPrice) { model.data.button = data.object.pricesCurrent.prices.customerPrice; }
|
154
|
+
}
|
155
|
+
if (data.object.assortmentObjects) {
|
156
|
+
// attach thumbnail image
|
157
|
+
let thumbnail = Assortments._getAssortmentObject(data.object.assortmentObjects, imageAssortmentKey);
|
158
|
+
if (thumbnail) model.data.thumbnail = thumbnail;
|
159
|
+
// attach bottleImage
|
160
|
+
let bottleImage = Assortments._getAssortmentObject(data.object.assortmentObjects, imageMediumCutout);
|
161
|
+
if (bottleImage) model.data.bottleImage = bottleImage;
|
162
|
+
// attach tickpoints
|
163
|
+
let tickpoints = Assortments._getAssortmentObject(data.object.assortmentObjects, 'whatWeThink');
|
164
|
+
if (tickpoints) model.data.tickpoints = tickpoints;
|
165
|
+
let tickpointsCase = Assortments._getAssortmentObject(data.object.assortmentObjects, 'whatWeSay');
|
166
|
+
if (tickpointsCase) model.data.tickpointsCase = tickpointsCase;
|
167
|
+
}
|
168
|
+
// attach style data
|
169
|
+
if (data.object.taste) {
|
170
|
+
model.data.style = this._getWineStyleByName(data.object.taste);
|
171
|
+
// attach sub style data (modern/classic)
|
172
|
+
if (data.object.productSubStyle) { model.data.style.subStyle = data.object.productSubStyle.toLowerCase(); }
|
173
|
+
}
|
174
|
+
// attach producer data
|
175
|
+
if (data.object.producer) {
|
176
|
+
model.data.producer.firstName = data.object.producer.firstName;
|
177
|
+
model.data.producer.lastName = data.object.producer.lastName;
|
178
|
+
model.data.producer.url = data.object.producer.url;
|
179
|
+
model.data.producer.urlString = data.object.producer.urlString;
|
180
|
+
}
|
181
|
+
// attach url
|
182
|
+
if (data.object.url) { model.data.url = data.object.url; }
|
183
|
+
// attach percentage match and like this
|
184
|
+
if (data.object.customerProductLikeThis) {
|
185
|
+
let likeData = data.object.customerProductLikeThis;
|
186
|
+
|
187
|
+
if (likeData.hasOwnProperty('likeThis')) { model.data.likeThis = likeData.likeThis; }
|
188
|
+
|
189
|
+
if (likeData.custProdRecommendation && likeData.custProdRecommendation.hasOwnProperty('score')) {
|
190
|
+
model.data.percentageMatch = likeData.custProdRecommendation.score;
|
191
|
+
const percVal = likeData.custProdRecommendation.score;
|
192
|
+
let formatted = (typeof percVal !== 'number') ? percVal : `${(percVal * 100).toFixed(0)}%`;
|
193
|
+
model.data.percentageMatchFormatted = formatted;
|
194
|
+
model.data.subHeading = formatted + ' Match';
|
195
|
+
}
|
196
|
+
}
|
197
|
+
// attach type description
|
198
|
+
if (data.object.productTypeDesc) { model.data.productTypeDesc = data.object.productTypeDesc; }
|
199
|
+
// attach product quantity
|
200
|
+
if (data.object.productQuantity) { model.data.productQuantity = data.object.productQuantity; }
|
201
|
+
// attached bottle quantity
|
202
|
+
if(data.object.quantity) { model.data.quantity = data.object.quantity; }
|
203
|
+
// attach scheme
|
204
|
+
if (data.object.scheme && data.object.scheme.id) { model.data.scheme = data.object.scheme; }
|
205
|
+
// attach assortment objects
|
206
|
+
if (data.object.assortmentObjects && data.object.assortmentObjects.objects && data.object.assortmentObjects.objects.length > 0) {
|
207
|
+
data.object.assortmentObjects.objects.forEach(ao => {
|
208
|
+
model.data.assortmentObjects[ao.name] = ao;
|
209
|
+
});
|
210
|
+
}
|
211
|
+
// attach shipping data
|
212
|
+
if (data.object.hasOwnProperty('shipAsCase')) { model.data.shipAsCase = data.object.shipAsCase; }
|
213
|
+
if (data.object.hasOwnProperty('packingSlots')) { model.data.packingSlots = data.object.packingSlots; }
|
214
|
+
// attach more info
|
215
|
+
if (data.object.hasOwnProperty('origin')) { model.data.origin = data.object.origin; }
|
216
|
+
if (data.object.hasOwnProperty('taste')) { model.data.taste = data.object.taste; }
|
217
|
+
if (data.object.hasOwnProperty('wineGrape')) { model.data.wineGrape = data.object.wineGrape; }
|
218
|
+
if (data.object.hasOwnProperty('hideFromView')) { model.data.hideFromView = data.object.hideFromView; }
|
219
|
+
if (data.object.hasOwnProperty('specialDelivery')) { model.data.specialDelivery = data.object.specialDelivery; }
|
220
|
+
if (data.object.hasOwnProperty('freeShipping')) { model.data.freeShipping = data.object.freeShipping; }
|
221
|
+
if (data.object.productRatingBreakdownList && data.object.productRatingBreakdownList.length > 0) { model.data.bia = data.object.productRatingBreakdownList[0]; }
|
222
|
+
if (data.object.hasOwnProperty('vegan')) { model.data.vegan = data.object.vegan; }
|
223
|
+
if (data.object.hasOwnProperty('vegetarian')) { model.data.vegetarian = data.object.vegetarian; }
|
224
|
+
if (data.object.hasOwnProperty('alcoholStrength')) { model.data.alcoholStrength = data.object.alcoholStrength; }
|
225
|
+
if (data.object.hasOwnProperty('bottleSizeDesc')) { model.data.bottleSizeDesc = data.object.bottleSizeDesc; }
|
226
|
+
if (data.object.hasOwnProperty('averageRating')) { model.data.averageRating = data.object.averageRating; }
|
227
|
+
if (data.object.hasOwnProperty('region')) { model.data.region = data.object.region; }
|
228
|
+
// for free bottles
|
229
|
+
if(data.promotionalPrice !== null && data.promotionalPrice === 0) { model.data.promotionalPrice = data.promotionalPrice; }
|
230
|
+
if(data.angelPrices !== null) { model.data.angelPrices = data.angelPrices; }
|
231
|
+
}
|
232
|
+
catch(error) { console.error('_parseProduct skipping item', error); return null; }
|
233
|
+
return model;
|
234
|
+
},
|
235
|
+
|
236
|
+
// get the wine style from data prop
|
237
|
+
_getWineStyleByName(styleName) {
|
238
|
+
let result = {};
|
239
|
+
if (!styleName) return result;
|
240
|
+
if (styleNamesIds[styleName]) {
|
241
|
+
let styleId = styleNamesIds[styleName];
|
242
|
+
let colours = styleColours[styleId];
|
243
|
+
result = {
|
244
|
+
name: styleName,
|
245
|
+
id: styleId,
|
246
|
+
colours: colours
|
247
|
+
};
|
248
|
+
}
|
249
|
+
return result;
|
250
|
+
},
|
251
|
+
};
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/**
|
2
|
+
* Method used for creating the computed breakpoint objects
|
3
|
+
* for use.
|
4
|
+
* @param {[Object, Number]} propToUse - the prop to use for creating the object
|
5
|
+
* @param {Object} defaults - default settings to use
|
6
|
+
* @return {Object} - containing breakpoints and values
|
7
|
+
*/
|
8
|
+
export function getResponsiveOption(propToUse, defaults) {
|
9
|
+
if (propToUse && typeof propToUse === 'object') {
|
10
|
+
let obj = {};
|
11
|
+
for (let index = 0; index < Object.keys(defaults).length; index++) {
|
12
|
+
const breakpointProp = Object.keys(defaults)[index];
|
13
|
+
const breakpointPropValue = propToUse[breakpointProp];
|
14
|
+
// if propToUse declares a breakpoint, apply to this breakpoint and up
|
15
|
+
if (breakpointPropValue || (typeof breakpointPropValue === 'number' && breakpointPropValue === 0)) {
|
16
|
+
for (let remaining = index; remaining < Object.keys(defaults).length; remaining++) {
|
17
|
+
obj[Object.keys(defaults)[remaining]] = breakpointPropValue;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
// fallback if not created yet, uses defaults equivalent value
|
21
|
+
else if (!obj[breakpointProp]) {
|
22
|
+
obj[breakpointProp] = defaults[breakpointProp];
|
23
|
+
}
|
24
|
+
}
|
25
|
+
return obj;
|
26
|
+
}
|
27
|
+
else if (propToUse && typeof propToUse === 'number') {
|
28
|
+
// Number defined, apply to all breakpoints
|
29
|
+
let obj = {};
|
30
|
+
for (let index = 0; index < Object.keys(defaults).length; index++) {
|
31
|
+
const breakpointProp = Object.keys(defaults)[index];
|
32
|
+
obj[breakpointProp] = propToUse;
|
33
|
+
}
|
34
|
+
return obj;
|
35
|
+
}
|
36
|
+
else {
|
37
|
+
// if responsive prop not defined, just use defaults
|
38
|
+
return defaults;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
import { breakpoints } from './variables.js';
|
43
|
+
export function getCurrentBreakpoint() {
|
44
|
+
let ret;
|
45
|
+
for (let index = 0; index < Object.keys(breakpoints).length; index++) {
|
46
|
+
const breakProp = Object.keys(breakpoints)[index];
|
47
|
+
if (window.innerWidth < breakpoints[breakProp]) {
|
48
|
+
ret = (index === 0) ? 'xs' : Object.keys(breakpoints)[index-1];
|
49
|
+
break;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
return ret ? ret : 'xl';
|
53
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export function getValidationMessage(element, options) {
|
2
|
+
const defaults = {
|
3
|
+
fallback: 'Input not valid, please try something else'
|
4
|
+
};
|
5
|
+
const opt = Object.assign({}, defaults, options);
|
6
|
+
|
7
|
+
return element.validationMessage != null ? element.validationMessage : opt.fallback;
|
8
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import sassBreakpoints from '../styles/js-modules/breakpoints.scss';
|
2
|
+
|
3
|
+
export const breakpoints = {
|
4
|
+
xs: parseInt(sassBreakpoints.breakpointXs), // mobile min (iphone 5/se)
|
5
|
+
sm: parseInt(sassBreakpoints.breakpointSm), // large mobile
|
6
|
+
md: parseInt(sassBreakpoints.breakpointMd), // tablet
|
7
|
+
lg: parseInt(sassBreakpoints.breakpointLg), // desktop
|
8
|
+
xl: parseInt(sassBreakpoints.breakpointXl), // wide
|
9
|
+
};
|
10
|
+
|
11
|
+
export const styleNamesIds = {
|
12
|
+
'Crisp White': 'WHITE_CRISP',
|
13
|
+
'Fruity White': 'WHITE_FRUITY',
|
14
|
+
'Rich White': 'WHITE_RICH',
|
15
|
+
'Sweet White': 'WHITE_SWEET',
|
16
|
+
'Fruity Red': 'RED_FRUITY',
|
17
|
+
'Smooth Red': 'RED_SMOOTH',
|
18
|
+
'Big Red': 'RED_BIG',
|
19
|
+
'Rose': 'ROSE',
|
20
|
+
'Sparkling': 'SPARKLING',
|
21
|
+
'Dessert & Fortified': 'DESSERT_FORTIFIED'
|
22
|
+
};
|
23
|
+
|
24
|
+
export const styleIdsNames = {
|
25
|
+
WHITE_CRISP: 'Crisp White',
|
26
|
+
WHITE_FRUITY: 'Fruity White',
|
27
|
+
WHITE_RICH: 'Rich White',
|
28
|
+
WHITE_SWEET: 'Sweet White',
|
29
|
+
RED_FRUITY: 'Fruity Red',
|
30
|
+
RED_SMOOTH: 'Smooth Red',
|
31
|
+
RED_BIG: 'Big Red',
|
32
|
+
ROSE: 'Rosé',
|
33
|
+
SPARKLING: 'Sparkling',
|
34
|
+
DESSERT_FORTIFIED: 'Dessert & Fortified'
|
35
|
+
};
|
36
|
+
|
37
|
+
export const styleColours = {
|
38
|
+
WHITE_CRISP: { primary: '#CCD402', secondary: '#BAC106' },
|
39
|
+
WHITE_FRUITY: { primary: '#5A8C24', secondary: '#4F7A17' },
|
40
|
+
WHITE_RICH: { primary: '#E8BC02', secondary: '#D4AC04' },
|
41
|
+
WHITE_SWEET: { primary: '#01A6B4', secondary: '#068F9A' },
|
42
|
+
RED_FRUITY: { primary: '#AC0F63', secondary: '#8E0C51' },
|
43
|
+
RED_SMOOTH: { primary: '#E4481D', secondary: '#CF3D15' },
|
44
|
+
RED_BIG: { primary: '#552681', secondary: '#451B6D' },
|
45
|
+
ROSE: { primary: '#E86D83', secondary: '#DC6378' },
|
46
|
+
SPARKLING: { primary: '#AC8A4D', secondary: '#9C7C43' },
|
47
|
+
DESSERT_FORTIFIED: { primary: '#151432', secondary: '#06061C' },
|
48
|
+
};
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import { convertStyleCodeToClassName } from '../globals/functions';
|
2
|
+
import { Products } from '../globals/products.js';
|
3
|
+
const bottleShotPlaceHolderPath = '/merchandising/content/placeholders/wine-bottle-placeholder.png';
|
4
|
+
|
5
|
+
const productCard = {
|
6
|
+
props: {
|
7
|
+
product: {
|
8
|
+
type: Object,
|
9
|
+
required: false
|
10
|
+
},
|
11
|
+
recommendationType: {
|
12
|
+
type: String,
|
13
|
+
required: false,
|
14
|
+
default: 'bia'
|
15
|
+
},
|
16
|
+
styleBar: {
|
17
|
+
type: Boolean,
|
18
|
+
required: false,
|
19
|
+
default: false
|
20
|
+
},
|
21
|
+
type: {
|
22
|
+
type: String,
|
23
|
+
required: false
|
24
|
+
}
|
25
|
+
},
|
26
|
+
|
27
|
+
computed: {
|
28
|
+
productData() {
|
29
|
+
let product = this.product;
|
30
|
+
|
31
|
+
if(product && product.data) {
|
32
|
+
return product.data
|
33
|
+
} else {
|
34
|
+
return null;
|
35
|
+
}
|
36
|
+
},
|
37
|
+
|
38
|
+
typeBia() {
|
39
|
+
return this.recommendationType === 'bia' &&
|
40
|
+
this.productData.bia &&
|
41
|
+
this.productData.bia.positiveRatingPercentage;
|
42
|
+
},
|
43
|
+
|
44
|
+
typePercentagematch() {
|
45
|
+
return this.recommendationType === 'percentageMatch' &&
|
46
|
+
this.productData.percentageMatchFormatted;
|
47
|
+
},
|
48
|
+
|
49
|
+
percentageMatchNumber() {
|
50
|
+
let score = null,
|
51
|
+
productData = this.productData;
|
52
|
+
|
53
|
+
if(
|
54
|
+
productData.customerProductLikeThis &&
|
55
|
+
productData.customerProductLikeThis.custProdRecommendation &&
|
56
|
+
productData.customerProductLikeThis.custProdRecommendation.score
|
57
|
+
) {
|
58
|
+
score = productData.customerProductLikeThis.custProdRecommendation.score;
|
59
|
+
score * 100;
|
60
|
+
}
|
61
|
+
|
62
|
+
return score;
|
63
|
+
},
|
64
|
+
|
65
|
+
itemPriceString() { return `${this.currencySymbol == '$' ? '$' : '£'}${this.productData.pricesCurrent.prices.customerPrice.toFixed(2)}` },
|
66
|
+
|
67
|
+
productImage() {
|
68
|
+
if (this.productData.bottleImage) { return window.staticImageUrl + this.productData.bottleImage; }
|
69
|
+
else {
|
70
|
+
let find = false;
|
71
|
+
|
72
|
+
if (this.productData.assortmentObjects.objects) {
|
73
|
+
find = this.productData.assortmentObjects.objects.findIndex(item => item.name == "mediumCutout");
|
74
|
+
}
|
75
|
+
|
76
|
+
if(find) {
|
77
|
+
return window.staticImageUrl + this.productData.assortmentObjects.objects[find].contentPath;
|
78
|
+
} else {
|
79
|
+
return window.staticImageUrl + bottleShotPlaceHolderPath;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
},
|
83
|
+
|
84
|
+
caseImage() {
|
85
|
+
// TODO: Tidy up - maybe include default placeholder image here if not available?
|
86
|
+
if (this.productData.bottleImage) { return window.staticImageUrl + this.productData.bottleImage; }
|
87
|
+
else { return window.staticImageUrl + this.productData.assortmentObjects.headline.contentPath; }
|
88
|
+
},
|
89
|
+
|
90
|
+
hasActionSlot() {
|
91
|
+
return !!this.$slots.action
|
92
|
+
}
|
93
|
+
},
|
94
|
+
|
95
|
+
methods: {
|
96
|
+
styleCodeClassName(product) {
|
97
|
+
if(product && product.style && product.style.id) {
|
98
|
+
return convertStyleCodeToClassName(product.style.id)
|
99
|
+
} else {
|
100
|
+
return null;
|
101
|
+
}
|
102
|
+
},
|
103
|
+
|
104
|
+
bottleShot(product) {
|
105
|
+
if (product.bottleImage) {
|
106
|
+
return window.staticImageUrl + product.bottleImage;
|
107
|
+
} else {
|
108
|
+
let find = false;
|
109
|
+
|
110
|
+
if (product.assortmentObjects.objects) {
|
111
|
+
find = product.assortmentObjects.objects.findIndex(item => item.name == "mediumCutout");
|
112
|
+
}
|
113
|
+
|
114
|
+
if(find) {
|
115
|
+
return window.staticImageUrl + product.assortmentObjects.objects[find].contentPath;
|
116
|
+
} else {
|
117
|
+
return window.staticImageUrl + bottleShotPlaceHolderPath;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
},
|
121
|
+
|
122
|
+
parentElement() {
|
123
|
+
return this.$el.parentElement;
|
124
|
+
},
|
125
|
+
|
126
|
+
atb: function() {
|
127
|
+
if (!this.productData.id) { return false; }
|
128
|
+
Products.addToBasket({ productId: this.productData.id, quantity: 1 })
|
129
|
+
.then(() => {
|
130
|
+
if (window.nkd && window.nkd.headerCart) { window.nkd.headerCart.reload(); }
|
131
|
+
window.notificationCentre.notify({
|
132
|
+
title: `1x ${this.productData.heading} added to your basket.`,
|
133
|
+
text: 'To checkout, please go to the basket page.',
|
134
|
+
group: 'header',
|
135
|
+
duration: 8000
|
136
|
+
});
|
137
|
+
});
|
138
|
+
},
|
139
|
+
goToUrl: function() { window.location = this.productData.url; }
|
140
|
+
},
|
141
|
+
|
142
|
+
filters: {
|
143
|
+
nameChopper: function(val) {
|
144
|
+
if (!val) { return false; }
|
145
|
+
const maxCharactersTitle = 42;
|
146
|
+
return val.length >= maxCharactersTitle ? `${val.substring(0, maxCharactersTitle)} ...` : val;
|
147
|
+
},
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
export default productCard;
|
package/index.js
DELETED
File without changes
|