@nuskin/cs-product-lib 1.0.2-cx12-6001.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/csProduct.js +422 -418
package/package.json
CHANGED
package/src/csProduct.js
CHANGED
|
@@ -1,418 +1,422 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const helpers = require('./helpers')
|
|
4
|
-
const { getProductStatus } = require('./productStatus')
|
|
5
|
-
const { deliveryAxios } = require('./axiosClient')
|
|
6
|
-
const { formatTranslations } = require('./formatTranslations')
|
|
7
|
-
const { formatVariant } = require('./formatVariant')
|
|
8
|
-
const { formatProduct } = require('./formatProduct')
|
|
9
|
-
const { transformBundle } = require('./transformBundle')
|
|
10
|
-
|
|
11
|
-
const validateConfig = (props) => {
|
|
12
|
-
if (!props) {
|
|
13
|
-
throw new Error(
|
|
14
|
-
`This will not work without a valid configuration {apiKey, environment, deliveryToken, homeUrl, awsBase, clientId}.`
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const requiredProps =[
|
|
19
|
-
"apiKey",
|
|
20
|
-
"environment",
|
|
21
|
-
"deliveryToken",
|
|
22
|
-
"homeUrl",
|
|
23
|
-
"awsBase",
|
|
24
|
-
"clientId"
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
requiredProps.forEach(prop => {
|
|
28
|
-
if (!props[prop]) {
|
|
29
|
-
throw new Error(`Missing required property ${prop} in config.`)
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/* istanbul ignore next */
|
|
35
|
-
const csProduct = (props) => {
|
|
36
|
-
const DEV_ENVIRONMENT = 'public-dev'
|
|
37
|
-
const VARIANTS = 'variants'
|
|
38
|
-
const KEY_INGREDIENTS = 'ingredients.key_ingredients'
|
|
39
|
-
const PRODUCT_HIGHLIGHTS = 'product_details.highlights'
|
|
40
|
-
const VARIANT_HIGHLIGHTS = 'variants.product_details.highlights'
|
|
41
|
-
const VARIANT_KEY_INGREDIENTS =
|
|
42
|
-
'variants.ingredients_override.key_ingredients'
|
|
43
|
-
const PRODUCT_FAQS = 'faqs'
|
|
44
|
-
const VARIANT_FAQS = 'variants.faqs'
|
|
45
|
-
const PRODUCT_RESOURCES = 'resources'
|
|
46
|
-
const VARIANT_RESOURCES = 'variants.resources'
|
|
47
|
-
const PRODUCT_CATEGORY = 'categories'
|
|
48
|
-
const PRODUCT_SUBCATEGORIES = 'categories.subcategories'
|
|
49
|
-
const PRODUCT_BRAND_STYLE = 'features.brand_style';
|
|
50
|
-
const DEFAULT_LOCALE = 'en'
|
|
51
|
-
const PRODUCT_TYPE = 'product'
|
|
52
|
-
const INCLUDE_FALLBACK = '&include_fallback=true'
|
|
53
|
-
const REQUIRED = 'required_products.product.'
|
|
54
|
-
const OPTIONAL = 'optional_products.product.'
|
|
55
|
-
const BUNDLE_TYPE = 'bundle'
|
|
56
|
-
|
|
57
|
-
// eslint-disable-next-line max-len
|
|
58
|
-
const productIncludes = `&include[]=${VARIANTS}&include[]=${PRODUCT_FAQS}&include[]=${KEY_INGREDIENTS}&include[]=${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_RESOURCES}&include[]=${VARIANT_KEY_INGREDIENTS}&include[]=${VARIANT_HIGHLIGHTS}&include[]=${VARIANT_FAQS}&include[]=${VARIANT_RESOURCES}&include[]=${PRODUCT_CATEGORY}&include[]=${PRODUCT_SUBCATEGORIES}&include[]=${PRODUCT_BRAND_STYLE}`
|
|
59
|
-
const requiredIncludes = `&include[]=${REQUIRED}${VARIANTS}&include[]=${REQUIRED}${PRODUCT_FAQS}&include[]=${REQUIRED}${KEY_INGREDIENTS}&include[]=${REQUIRED}${PRODUCT_HIGHLIGHTS}&include[]=${REQUIRED}${PRODUCT_RESOURCES}&include[]=${REQUIRED}${VARIANT_KEY_INGREDIENTS}&include[]=${REQUIRED}${VARIANT_HIGHLIGHTS}&include[]=${REQUIRED}${VARIANT_FAQS}&include[]=${REQUIRED}${VARIANT_RESOURCES}&include[]=${REQUIRED}${PRODUCT_CATEGORY}&include[]=${REQUIRED}${PRODUCT_SUBCATEGORIES}`
|
|
60
|
-
const optionalIncludes = `&include[]=${OPTIONAL}${VARIANTS}&include[]=${OPTIONAL}${PRODUCT_FAQS}&include[]=${OPTIONAL}${KEY_INGREDIENTS}&include[]=${OPTIONAL}${PRODUCT_HIGHLIGHTS}&include[]=${OPTIONAL}${PRODUCT_RESOURCES}&include[]=${OPTIONAL}${VARIANT_KEY_INGREDIENTS}&include[]=${OPTIONAL}${VARIANT_HIGHLIGHTS}&include[]=${OPTIONAL}${VARIANT_FAQS}&include[]=${OPTIONAL}${VARIANT_RESOURCES}&include[]=${OPTIONAL}${PRODUCT_CATEGORY}&include[]=${OPTIONAL}${PRODUCT_SUBCATEGORIES}`
|
|
61
|
-
|
|
62
|
-
validateConfig(props)
|
|
63
|
-
const { apiKey, environment, deliveryToken, ...config } = props
|
|
64
|
-
const axios = deliveryAxios({ apiKey, deliveryToken})
|
|
65
|
-
|
|
66
|
-
const asObject = () => {
|
|
67
|
-
return props
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const removeInvalidVariants = async (products, locale, translations) => {
|
|
71
|
-
const validSkus = []
|
|
72
|
-
for (const product of products) {
|
|
73
|
-
for (const variant of product?.variants || []) {
|
|
74
|
-
const bestSkuData = helpers?.getBestSkuData(variant) || []
|
|
75
|
-
if (bestSkuData && Object.keys(bestSkuData)?.length > 0) {
|
|
76
|
-
validSkus.push(bestSkuData.sku)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (environment === 'public-dev' && validSkus?.length === 0) return
|
|
81
|
-
|
|
82
|
-
const localeData = helpers?.parseLocale(locale)
|
|
83
|
-
locale = helpers?.reorderLocale(locale)
|
|
84
|
-
let status = {}
|
|
85
|
-
let marketData = {}
|
|
86
|
-
if (validSkus?.length > 0) {
|
|
87
|
-
status = await getProductStatus(validSkus, locale, config)
|
|
88
|
-
const localeSplit = locale.split('_')
|
|
89
|
-
let market =
|
|
90
|
-
localeSplit?.length > 1 ? localeSplit[1].toUpperCase() : 'XX'
|
|
91
|
-
if (market === 'XX') {
|
|
92
|
-
const split2 = locale.split('-')
|
|
93
|
-
market = split2.length > 1 ? split2[0].toUpperCase() : ''
|
|
94
|
-
}
|
|
95
|
-
marketData = await getEntriesByQuery({
|
|
96
|
-
contentType: 'market',
|
|
97
|
-
query: `{"iso_code_2": "${market}"}`,
|
|
98
|
-
locale: 'en'
|
|
99
|
-
})
|
|
100
|
-
if (marketData?.length > 0) {
|
|
101
|
-
marketData = marketData[0]
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const product of products) {
|
|
105
|
-
const validVariants = []
|
|
106
|
-
for (const variant of product?.variants || []) {
|
|
107
|
-
const bestSkuData = helpers?.getBestSkuData(variant)
|
|
108
|
-
if (bestSkuData.sku) {
|
|
109
|
-
const varStatus = status[bestSkuData.sku]
|
|
110
|
-
if (varStatus && varStatus.status.retail) {
|
|
111
|
-
variant.sap_data.sku_data = [bestSkuData]
|
|
112
|
-
validVariants.push({
|
|
113
|
-
...variant,
|
|
114
|
-
status: varStatus,
|
|
115
|
-
marketData
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
product.variants = validVariants
|
|
121
|
-
product.translations = Array.isArray(translations)
|
|
122
|
-
? translations[0]
|
|
123
|
-
: translations
|
|
124
|
-
product.localeData = localeData
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const parseSharedStrings = async (translations) => {
|
|
129
|
-
if (helpers?.isIterable(translations)) {
|
|
130
|
-
for (const translation of translations) {
|
|
131
|
-
translation.common_strings = translation?.common_strings
|
|
132
|
-
?.map((obj) => {
|
|
133
|
-
const commonStrings = { type: obj.key }
|
|
134
|
-
// eslint-disable-next-line no-sequences
|
|
135
|
-
commonStrings.strings = (
|
|
136
|
-
(obj || {}).strings || []
|
|
137
|
-
).reduce(
|
|
138
|
-
(result, { key, value }) => (
|
|
139
|
-
(result[key] = value), result
|
|
140
|
-
),
|
|
141
|
-
{}
|
|
142
|
-
)
|
|
143
|
-
return commonStrings
|
|
144
|
-
})
|
|
145
|
-
.reduce((result, { type, strings }) => {
|
|
146
|
-
result[type] = strings
|
|
147
|
-
return result
|
|
148
|
-
}, {})
|
|
149
|
-
translation.subscriptions = helpers.mapSubscriptions(translation?.subscriptions)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const formatProductWithSchima = (products = []) => {
|
|
155
|
-
return products?.map((product) => {
|
|
156
|
-
const formatedProduct = formatProduct(product, config)
|
|
157
|
-
formatedProduct.variants = formatedProduct?.variants?.map(
|
|
158
|
-
(variant) => formatVariant(variant)
|
|
159
|
-
)
|
|
160
|
-
return formatedProduct
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const formatBundleWithSchima = (bundles = []) => {
|
|
165
|
-
return bundles?.map((bundle) => {
|
|
166
|
-
const formatedBundle = transformBundle(bundle, config)
|
|
167
|
-
|
|
168
|
-
formatedBundle.requiredProducts = formatedBundle?.requiredProducts?.map(
|
|
169
|
-
({product, quantity}) => {
|
|
170
|
-
const [formatedProduct] = formatProductWithSchima([product])
|
|
171
|
-
return {product : formatedProduct, quantity}
|
|
172
|
-
}
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
formatedBundle.optionalProducts = formatedBundle?.optionalProducts?.map(
|
|
176
|
-
({product, quantity}) => {
|
|
177
|
-
const [formatedProduct] = formatProductWithSchima([product])
|
|
178
|
-
return {product : formatedProduct, quantity}
|
|
179
|
-
}
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
return formatedBundle
|
|
183
|
-
})
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// includes is an array of all the referenced types in the contentType you are requesting that should be resolved
|
|
187
|
-
// and returned (Example: ['common_strings'])
|
|
188
|
-
const getEntriesByQuery = async ({
|
|
189
|
-
contentType = PRODUCT_TYPE,
|
|
190
|
-
query = '',
|
|
191
|
-
locale = DEFAULT_LOCALE,
|
|
192
|
-
includes,
|
|
193
|
-
start = 0,
|
|
194
|
-
limit = 50,
|
|
195
|
-
onlyEntries = true
|
|
196
|
-
}) => {
|
|
197
|
-
// eslint-disable-next-line max-len
|
|
198
|
-
let url = `content_types/${contentType}/entries?environment=${environment}&locale=${locale}&include_count=true&limit=${limit}&query=${query}`
|
|
199
|
-
if (contentType === PRODUCT_TYPE) {
|
|
200
|
-
url += productIncludes
|
|
201
|
-
}
|
|
202
|
-
if (contentType === BUNDLE_TYPE) {
|
|
203
|
-
url += requiredIncludes
|
|
204
|
-
url += optionalIncludes
|
|
205
|
-
}
|
|
206
|
-
if (includes) {
|
|
207
|
-
for (const include of includes) {
|
|
208
|
-
url += `&include[]=${include}`
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (environment === DEV_ENVIRONMENT) {
|
|
212
|
-
url += INCLUDE_FALLBACK
|
|
213
|
-
}
|
|
214
|
-
if (start > 0) {
|
|
215
|
-
url += `&skip=${start}`
|
|
216
|
-
}
|
|
217
|
-
try {
|
|
218
|
-
const res = await axios(url)
|
|
219
|
-
|
|
220
|
-
if (onlyEntries)
|
|
221
|
-
return res?.data?.entries ? res.data.entries : res;
|
|
222
|
-
else
|
|
223
|
-
return res?.data?.entries ? res.data : res;
|
|
224
|
-
} catch (error) {
|
|
225
|
-
return error
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const queryProducts = async (query, locale) => {
|
|
230
|
-
const products = await getEntriesByQuery({ query, locale })
|
|
231
|
-
return products
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const getBundle = async (id, locale) => {
|
|
235
|
-
const query = `{ "$or": [{ "bundle_id": { "$in": ["${id}"]}}, { "uid": { "$in": ["${id}"] }}] }`
|
|
236
|
-
const bundles = await getEntriesByQuery({
|
|
237
|
-
query,
|
|
238
|
-
locale,
|
|
239
|
-
contentType: BUNDLE_TYPE
|
|
240
|
-
})
|
|
241
|
-
const translations = await getTranslations(locale)
|
|
242
|
-
|
|
243
|
-
for (let b = 0; b < bundles.length; b++) {
|
|
244
|
-
for (
|
|
245
|
-
let i = 0;
|
|
246
|
-
i < (bundles[b].required_products || []).length;
|
|
247
|
-
i++
|
|
248
|
-
) {
|
|
249
|
-
await removeInvalidVariants(
|
|
250
|
-
bundles[b].required_products[i].product,
|
|
251
|
-
locale,
|
|
252
|
-
translations
|
|
253
|
-
)
|
|
254
|
-
}
|
|
255
|
-
for (
|
|
256
|
-
let i = 0;
|
|
257
|
-
i < (bundles[b].optional_products || []).length;
|
|
258
|
-
i++
|
|
259
|
-
) {
|
|
260
|
-
await removeInvalidVariants(
|
|
261
|
-
bundles[b].optional_products[i].product,
|
|
262
|
-
locale,
|
|
263
|
-
translations
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return formatBundleWithSchima(bundles)?.[0]
|
|
268
|
-
}
|
|
269
|
-
const getBundles = async (ids, locale) => {
|
|
270
|
-
const query = `{ "$or": [{ "bundle_id": { "$in": ${helpers?.arrayString(ids)} }}, { "uid": { "$in": ${helpers?.arrayString(ids)} }}] }`
|
|
271
|
-
const bundles = await getEntriesByQuery({
|
|
272
|
-
query,
|
|
273
|
-
locale,
|
|
274
|
-
contentType: BUNDLE_TYPE
|
|
275
|
-
})
|
|
276
|
-
const translations = await getTranslations(locale)
|
|
277
|
-
|
|
278
|
-
for (let b = 0; b < bundles.length; b++) {
|
|
279
|
-
for (
|
|
280
|
-
let i = 0;
|
|
281
|
-
i < (bundles[b].required_products || []).length;
|
|
282
|
-
i++
|
|
283
|
-
) {
|
|
284
|
-
await removeInvalidVariants(
|
|
285
|
-
bundles[b].required_products[i].product,
|
|
286
|
-
locale,
|
|
287
|
-
translations
|
|
288
|
-
)
|
|
289
|
-
}
|
|
290
|
-
for (
|
|
291
|
-
let i = 0;
|
|
292
|
-
i < (bundles[b].optional_products || []).length;
|
|
293
|
-
i++
|
|
294
|
-
) {
|
|
295
|
-
await removeInvalidVariants(
|
|
296
|
-
bundles[b].optional_products[i].product,
|
|
297
|
-
locale,
|
|
298
|
-
translations
|
|
299
|
-
)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return formatBundleWithSchima(bundles)
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const getProductsBySku = async (skus, locale) => {
|
|
306
|
-
if (!Array.isArray(skus)) {
|
|
307
|
-
skus = [skus]
|
|
308
|
-
}
|
|
309
|
-
const query = `{"variants": {"$in_query":{"sap_data.skus": {"$in": ${helpers?.arrayString(
|
|
310
|
-
skus
|
|
311
|
-
)}}}}}`
|
|
312
|
-
|
|
313
|
-
let products = await queryProducts(query, locale)
|
|
314
|
-
const translations = await getTranslations(locale)
|
|
315
|
-
// await parseSharedStrings(translations);
|
|
316
|
-
await removeInvalidVariants(products, locale, translations)
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const helpers = require('./helpers')
|
|
4
|
+
const { getProductStatus } = require('./productStatus')
|
|
5
|
+
const { deliveryAxios } = require('./axiosClient')
|
|
6
|
+
const { formatTranslations } = require('./formatTranslations')
|
|
7
|
+
const { formatVariant } = require('./formatVariant')
|
|
8
|
+
const { formatProduct } = require('./formatProduct')
|
|
9
|
+
const { transformBundle } = require('./transformBundle')
|
|
10
|
+
|
|
11
|
+
const validateConfig = (props) => {
|
|
12
|
+
if (!props) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`This will not work without a valid configuration {apiKey, environment, deliveryToken, homeUrl, awsBase, clientId}.`
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const requiredProps =[
|
|
19
|
+
"apiKey",
|
|
20
|
+
"environment",
|
|
21
|
+
"deliveryToken",
|
|
22
|
+
"homeUrl",
|
|
23
|
+
"awsBase",
|
|
24
|
+
"clientId"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
requiredProps.forEach(prop => {
|
|
28
|
+
if (!props[prop]) {
|
|
29
|
+
throw new Error(`Missing required property ${prop} in config.`)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* istanbul ignore next */
|
|
35
|
+
const csProduct = (props) => {
|
|
36
|
+
const DEV_ENVIRONMENT = 'public-dev'
|
|
37
|
+
const VARIANTS = 'variants'
|
|
38
|
+
const KEY_INGREDIENTS = 'ingredients.key_ingredients'
|
|
39
|
+
const PRODUCT_HIGHLIGHTS = 'product_details.highlights'
|
|
40
|
+
const VARIANT_HIGHLIGHTS = 'variants.product_details.highlights'
|
|
41
|
+
const VARIANT_KEY_INGREDIENTS =
|
|
42
|
+
'variants.ingredients_override.key_ingredients'
|
|
43
|
+
const PRODUCT_FAQS = 'faqs'
|
|
44
|
+
const VARIANT_FAQS = 'variants.faqs'
|
|
45
|
+
const PRODUCT_RESOURCES = 'resources'
|
|
46
|
+
const VARIANT_RESOURCES = 'variants.resources'
|
|
47
|
+
const PRODUCT_CATEGORY = 'categories'
|
|
48
|
+
const PRODUCT_SUBCATEGORIES = 'categories.subcategories'
|
|
49
|
+
const PRODUCT_BRAND_STYLE = 'features.brand_style';
|
|
50
|
+
const DEFAULT_LOCALE = 'en'
|
|
51
|
+
const PRODUCT_TYPE = 'product'
|
|
52
|
+
const INCLUDE_FALLBACK = '&include_fallback=true'
|
|
53
|
+
const REQUIRED = 'required_products.product.'
|
|
54
|
+
const OPTIONAL = 'optional_products.product.'
|
|
55
|
+
const BUNDLE_TYPE = 'bundle'
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line max-len
|
|
58
|
+
const productIncludes = `&include[]=${VARIANTS}&include[]=${PRODUCT_FAQS}&include[]=${KEY_INGREDIENTS}&include[]=${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_RESOURCES}&include[]=${VARIANT_KEY_INGREDIENTS}&include[]=${VARIANT_HIGHLIGHTS}&include[]=${VARIANT_FAQS}&include[]=${VARIANT_RESOURCES}&include[]=${PRODUCT_CATEGORY}&include[]=${PRODUCT_SUBCATEGORIES}&include[]=${PRODUCT_BRAND_STYLE}`
|
|
59
|
+
const requiredIncludes = `&include[]=${REQUIRED}${VARIANTS}&include[]=${REQUIRED}${PRODUCT_FAQS}&include[]=${REQUIRED}${KEY_INGREDIENTS}&include[]=${REQUIRED}${PRODUCT_HIGHLIGHTS}&include[]=${REQUIRED}${PRODUCT_RESOURCES}&include[]=${REQUIRED}${VARIANT_KEY_INGREDIENTS}&include[]=${REQUIRED}${VARIANT_HIGHLIGHTS}&include[]=${REQUIRED}${VARIANT_FAQS}&include[]=${REQUIRED}${VARIANT_RESOURCES}&include[]=${REQUIRED}${PRODUCT_CATEGORY}&include[]=${REQUIRED}${PRODUCT_SUBCATEGORIES}`
|
|
60
|
+
const optionalIncludes = `&include[]=${OPTIONAL}${VARIANTS}&include[]=${OPTIONAL}${PRODUCT_FAQS}&include[]=${OPTIONAL}${KEY_INGREDIENTS}&include[]=${OPTIONAL}${PRODUCT_HIGHLIGHTS}&include[]=${OPTIONAL}${PRODUCT_RESOURCES}&include[]=${OPTIONAL}${VARIANT_KEY_INGREDIENTS}&include[]=${OPTIONAL}${VARIANT_HIGHLIGHTS}&include[]=${OPTIONAL}${VARIANT_FAQS}&include[]=${OPTIONAL}${VARIANT_RESOURCES}&include[]=${OPTIONAL}${PRODUCT_CATEGORY}&include[]=${OPTIONAL}${PRODUCT_SUBCATEGORIES}`
|
|
61
|
+
|
|
62
|
+
validateConfig(props)
|
|
63
|
+
const { apiKey, environment, deliveryToken, ...config } = props
|
|
64
|
+
const axios = deliveryAxios({ apiKey, deliveryToken})
|
|
65
|
+
|
|
66
|
+
const asObject = () => {
|
|
67
|
+
return props
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const removeInvalidVariants = async (products, locale, translations) => {
|
|
71
|
+
const validSkus = []
|
|
72
|
+
for (const product of products) {
|
|
73
|
+
for (const variant of product?.variants || []) {
|
|
74
|
+
const bestSkuData = helpers?.getBestSkuData(variant) || []
|
|
75
|
+
if (bestSkuData && Object.keys(bestSkuData)?.length > 0) {
|
|
76
|
+
validSkus.push(bestSkuData.sku)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (environment === 'public-dev' && validSkus?.length === 0) return
|
|
81
|
+
|
|
82
|
+
const localeData = helpers?.parseLocale(locale)
|
|
83
|
+
locale = helpers?.reorderLocale(locale)
|
|
84
|
+
let status = {}
|
|
85
|
+
let marketData = {}
|
|
86
|
+
if (validSkus?.length > 0) {
|
|
87
|
+
status = await getProductStatus(validSkus, locale, config)
|
|
88
|
+
const localeSplit = locale.split('_')
|
|
89
|
+
let market =
|
|
90
|
+
localeSplit?.length > 1 ? localeSplit[1].toUpperCase() : 'XX'
|
|
91
|
+
if (market === 'XX') {
|
|
92
|
+
const split2 = locale.split('-')
|
|
93
|
+
market = split2.length > 1 ? split2[0].toUpperCase() : ''
|
|
94
|
+
}
|
|
95
|
+
marketData = await getEntriesByQuery({
|
|
96
|
+
contentType: 'market',
|
|
97
|
+
query: `{"iso_code_2": "${market}"}`,
|
|
98
|
+
locale: 'en'
|
|
99
|
+
})
|
|
100
|
+
if (marketData?.length > 0) {
|
|
101
|
+
marketData = marketData[0]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const product of products) {
|
|
105
|
+
const validVariants = []
|
|
106
|
+
for (const variant of product?.variants || []) {
|
|
107
|
+
const bestSkuData = helpers?.getBestSkuData(variant)
|
|
108
|
+
if (bestSkuData.sku) {
|
|
109
|
+
const varStatus = status[bestSkuData.sku]
|
|
110
|
+
if (varStatus && varStatus.status.retail) {
|
|
111
|
+
variant.sap_data.sku_data = [bestSkuData]
|
|
112
|
+
validVariants.push({
|
|
113
|
+
...variant,
|
|
114
|
+
status: varStatus,
|
|
115
|
+
marketData
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
product.variants = validVariants
|
|
121
|
+
product.translations = Array.isArray(translations)
|
|
122
|
+
? translations[0]
|
|
123
|
+
: translations
|
|
124
|
+
product.localeData = localeData
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const parseSharedStrings = async (translations) => {
|
|
129
|
+
if (helpers?.isIterable(translations)) {
|
|
130
|
+
for (const translation of translations) {
|
|
131
|
+
translation.common_strings = translation?.common_strings
|
|
132
|
+
?.map((obj) => {
|
|
133
|
+
const commonStrings = { type: obj.key }
|
|
134
|
+
// eslint-disable-next-line no-sequences
|
|
135
|
+
commonStrings.strings = (
|
|
136
|
+
(obj || {}).strings || []
|
|
137
|
+
).reduce(
|
|
138
|
+
(result, { key, value }) => (
|
|
139
|
+
(result[key] = value), result
|
|
140
|
+
),
|
|
141
|
+
{}
|
|
142
|
+
)
|
|
143
|
+
return commonStrings
|
|
144
|
+
})
|
|
145
|
+
.reduce((result, { type, strings }) => {
|
|
146
|
+
result[type] = strings
|
|
147
|
+
return result
|
|
148
|
+
}, {})
|
|
149
|
+
translation.subscriptions = helpers.mapSubscriptions(translation?.subscriptions)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const formatProductWithSchima = (products = []) => {
|
|
155
|
+
return products?.map((product) => {
|
|
156
|
+
const formatedProduct = formatProduct(product, config)
|
|
157
|
+
formatedProduct.variants = formatedProduct?.variants?.map(
|
|
158
|
+
(variant) => formatVariant(variant)
|
|
159
|
+
)
|
|
160
|
+
return formatedProduct
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const formatBundleWithSchima = (bundles = []) => {
|
|
165
|
+
return bundles?.map((bundle) => {
|
|
166
|
+
const formatedBundle = transformBundle(bundle, config)
|
|
167
|
+
|
|
168
|
+
formatedBundle.requiredProducts = formatedBundle?.requiredProducts?.map(
|
|
169
|
+
({product, quantity}) => {
|
|
170
|
+
const [formatedProduct] = formatProductWithSchima([product])
|
|
171
|
+
return {product : formatedProduct, quantity}
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
formatedBundle.optionalProducts = formatedBundle?.optionalProducts?.map(
|
|
176
|
+
({product, quantity}) => {
|
|
177
|
+
const [formatedProduct] = formatProductWithSchima([product])
|
|
178
|
+
return {product : formatedProduct, quantity}
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return formatedBundle
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// includes is an array of all the referenced types in the contentType you are requesting that should be resolved
|
|
187
|
+
// and returned (Example: ['common_strings'])
|
|
188
|
+
const getEntriesByQuery = async ({
|
|
189
|
+
contentType = PRODUCT_TYPE,
|
|
190
|
+
query = '',
|
|
191
|
+
locale = DEFAULT_LOCALE,
|
|
192
|
+
includes,
|
|
193
|
+
start = 0,
|
|
194
|
+
limit = 50,
|
|
195
|
+
onlyEntries = true
|
|
196
|
+
}) => {
|
|
197
|
+
// eslint-disable-next-line max-len
|
|
198
|
+
let url = `content_types/${contentType}/entries?environment=${environment}&locale=${locale}&include_count=true&limit=${limit}&query=${query}`
|
|
199
|
+
if (contentType === PRODUCT_TYPE) {
|
|
200
|
+
url += productIncludes
|
|
201
|
+
}
|
|
202
|
+
if (contentType === BUNDLE_TYPE) {
|
|
203
|
+
url += requiredIncludes
|
|
204
|
+
url += optionalIncludes
|
|
205
|
+
}
|
|
206
|
+
if (includes) {
|
|
207
|
+
for (const include of includes) {
|
|
208
|
+
url += `&include[]=${include}`
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (environment === DEV_ENVIRONMENT) {
|
|
212
|
+
url += INCLUDE_FALLBACK
|
|
213
|
+
}
|
|
214
|
+
if (start > 0) {
|
|
215
|
+
url += `&skip=${start}`
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const res = await axios(url)
|
|
219
|
+
|
|
220
|
+
if (onlyEntries)
|
|
221
|
+
return res?.data?.entries ? res.data.entries : res;
|
|
222
|
+
else
|
|
223
|
+
return res?.data?.entries ? res.data : res;
|
|
224
|
+
} catch (error) {
|
|
225
|
+
return error
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const queryProducts = async (query, locale) => {
|
|
230
|
+
const products = await getEntriesByQuery({ query, locale })
|
|
231
|
+
return products
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const getBundle = async (id, locale) => {
|
|
235
|
+
const query = `{ "$or": [{ "bundle_id": { "$in": ["${id}"]}}, { "uid": { "$in": ["${id}"] }}] }`
|
|
236
|
+
const bundles = await getEntriesByQuery({
|
|
237
|
+
query,
|
|
238
|
+
locale,
|
|
239
|
+
contentType: BUNDLE_TYPE
|
|
240
|
+
})
|
|
241
|
+
const translations = await getTranslations(locale)
|
|
242
|
+
|
|
243
|
+
for (let b = 0; b < bundles.length; b++) {
|
|
244
|
+
for (
|
|
245
|
+
let i = 0;
|
|
246
|
+
i < (bundles[b].required_products || []).length;
|
|
247
|
+
i++
|
|
248
|
+
) {
|
|
249
|
+
await removeInvalidVariants(
|
|
250
|
+
bundles[b].required_products[i].product,
|
|
251
|
+
locale,
|
|
252
|
+
translations
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
for (
|
|
256
|
+
let i = 0;
|
|
257
|
+
i < (bundles[b].optional_products || []).length;
|
|
258
|
+
i++
|
|
259
|
+
) {
|
|
260
|
+
await removeInvalidVariants(
|
|
261
|
+
bundles[b].optional_products[i].product,
|
|
262
|
+
locale,
|
|
263
|
+
translations
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return formatBundleWithSchima(bundles)?.[0]
|
|
268
|
+
}
|
|
269
|
+
const getBundles = async (ids, locale) => {
|
|
270
|
+
const query = `{ "$or": [{ "bundle_id": { "$in": ${helpers?.arrayString(ids)} }}, { "uid": { "$in": ${helpers?.arrayString(ids)} }}] }`
|
|
271
|
+
const bundles = await getEntriesByQuery({
|
|
272
|
+
query,
|
|
273
|
+
locale,
|
|
274
|
+
contentType: BUNDLE_TYPE
|
|
275
|
+
})
|
|
276
|
+
const translations = await getTranslations(locale)
|
|
277
|
+
|
|
278
|
+
for (let b = 0; b < bundles.length; b++) {
|
|
279
|
+
for (
|
|
280
|
+
let i = 0;
|
|
281
|
+
i < (bundles[b].required_products || []).length;
|
|
282
|
+
i++
|
|
283
|
+
) {
|
|
284
|
+
await removeInvalidVariants(
|
|
285
|
+
bundles[b].required_products[i].product,
|
|
286
|
+
locale,
|
|
287
|
+
translations
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
for (
|
|
291
|
+
let i = 0;
|
|
292
|
+
i < (bundles[b].optional_products || []).length;
|
|
293
|
+
i++
|
|
294
|
+
) {
|
|
295
|
+
await removeInvalidVariants(
|
|
296
|
+
bundles[b].optional_products[i].product,
|
|
297
|
+
locale,
|
|
298
|
+
translations
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return formatBundleWithSchima(bundles)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const getProductsBySku = async (skus, locale) => {
|
|
306
|
+
if (!Array.isArray(skus)) {
|
|
307
|
+
skus = [skus]
|
|
308
|
+
}
|
|
309
|
+
const query = `{"variants": {"$in_query":{"sap_data.skus": {"$in": ${helpers?.arrayString(
|
|
310
|
+
skus
|
|
311
|
+
)}}}}}`
|
|
312
|
+
|
|
313
|
+
let products = await queryProducts(query, locale)
|
|
314
|
+
const translations = await getTranslations(locale)
|
|
315
|
+
// await parseSharedStrings(translations);
|
|
316
|
+
await removeInvalidVariants(products, locale, translations)
|
|
317
|
+
for (const product of products) {
|
|
318
|
+
product.skus = skus
|
|
319
|
+
product.locale = locale
|
|
320
|
+
}
|
|
321
|
+
return formatProductWithSchima(products)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const getProductsByGlobalId = async (ids, locale) => {
|
|
325
|
+
if (!Array.isArray(ids)) {
|
|
326
|
+
ids = [ids]
|
|
327
|
+
}
|
|
328
|
+
const query = `{"variants": {"$in_query":{"sap_data.global_id": {"$in": ${helpers?.arrayString(
|
|
329
|
+
[ids]
|
|
330
|
+
)}}}}}`
|
|
331
|
+
|
|
332
|
+
let products = await queryProducts(query, locale)
|
|
333
|
+
const translations = await getTranslations(locale)
|
|
334
|
+
// await parseSharedStrings(translations);
|
|
335
|
+
await removeInvalidVariants(products, locale, translations)
|
|
336
|
+
return formatProductWithSchima(products)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const getProductsBySlug = async (slugs, locale) => {
|
|
340
|
+
if (!Array.isArray(slugs)) {
|
|
341
|
+
slugs = [slugs]
|
|
342
|
+
}
|
|
343
|
+
const query = `{"seo_information.slug": {"$in": ${helpers?.arrayString(
|
|
344
|
+
slugs
|
|
345
|
+
)}}}`
|
|
346
|
+
|
|
347
|
+
const products = await queryProducts(query, locale)
|
|
348
|
+
const translations = await getTranslations(locale)
|
|
349
|
+
// await parseSharedStrings(translations);
|
|
350
|
+
await removeInvalidVariants(products, locale, translations)
|
|
351
|
+
return formatProductWithSchima(products)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const getProductsByUID = async (ids, locale) => {
|
|
355
|
+
if (!Array.isArray(ids)) {
|
|
356
|
+
ids = [ids]
|
|
357
|
+
}
|
|
358
|
+
const query = `{"uid": {"$in": ${helpers?.arrayString(ids)}}}`
|
|
359
|
+
let products = await queryProducts(query, locale)
|
|
360
|
+
const translations = await getTranslations(locale)
|
|
361
|
+
// await parseSharedStrings(translations);
|
|
362
|
+
await removeInvalidVariants(products, locale, translations)
|
|
363
|
+
return formatProductWithSchima(products)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const getTranslations = async (locale) => {
|
|
367
|
+
const translations = await getEntriesByQuery({
|
|
368
|
+
contentType: 'strings_product_detail_page',
|
|
369
|
+
locale,
|
|
370
|
+
includes: ['common_strings', 'subscriptions.modal']
|
|
371
|
+
})
|
|
372
|
+
await parseSharedStrings(translations)
|
|
373
|
+
return translations
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const getProductTranslations = async (locale) => {
|
|
377
|
+
const translations = await getTranslations(locale)
|
|
378
|
+
const formatedTranslations = translations.map((translate) =>
|
|
379
|
+
formatTranslations(translate)
|
|
380
|
+
)
|
|
381
|
+
return formatedTranslations
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const publishedProducts = async ({ locale, skip = 0, limit = 50 } = {}) => {
|
|
385
|
+
let products = await getEntriesByQuery({
|
|
386
|
+
locale,
|
|
387
|
+
start: skip,
|
|
388
|
+
limit,
|
|
389
|
+
onlyEntries: false
|
|
390
|
+
})
|
|
391
|
+
const count = products?.count || 0
|
|
392
|
+
products = products?.entries || []
|
|
393
|
+
const translations = await getTranslations(locale)
|
|
394
|
+
await removeInvalidVariants(products, locale, translations)
|
|
395
|
+
const transformProduct = formatProductWithSchima(products)
|
|
396
|
+
return {
|
|
397
|
+
products: transformProduct,
|
|
398
|
+
validCount: products.length,
|
|
399
|
+
totalCount: count,
|
|
400
|
+
skip
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return {
|
|
405
|
+
asObject,
|
|
406
|
+
getEntriesByQuery,
|
|
407
|
+
getProductsBySku,
|
|
408
|
+
getProductsByGlobalId,
|
|
409
|
+
getProductsBySlug,
|
|
410
|
+
getProductsByUID,
|
|
411
|
+
getTranslations,
|
|
412
|
+
publishedProducts,
|
|
413
|
+
formatTranslations,
|
|
414
|
+
getProductTranslations,
|
|
415
|
+
getBundle,
|
|
416
|
+
getBundles
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
module.exports = {
|
|
421
|
+
csProduct
|
|
422
|
+
}
|