@nuskin/cs-product-lib 1.0.0 → 1.0.1-cx12-6830.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 +2 -1
- package/src/axiosClient.js +30 -0
- package/src/csProduct.js +272 -105
- package/src/formatProduct.js +81 -0
- package/src/formatTranslations.js +162 -0
- package/src/formatVariant.js +115 -0
- package/src/helpers.js +748 -218
- package/src/index.js +1 -0
- package/src/marketRegionMappings.js +65 -0
- package/src/productStatus.js +6 -3
- package/src/status.js +186 -0
- package/src/transformBundle.js +68 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/cs-product-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-cx12-6830.2",
|
|
4
4
|
"description": "Library for pulling and parsing product content (and applying business logic) retrieved from Contentstack",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@nuskin/ns-common-lib": "1.4.5",
|
|
41
41
|
"axios": "1.3.0",
|
|
42
42
|
"axios-retry": "3.4.0",
|
|
43
|
+
"config": "^3.3.6",
|
|
43
44
|
"entities": "4.4.0",
|
|
44
45
|
"lodash": "4.17.21",
|
|
45
46
|
"turndown": "7.1.1"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const axiosRetry = require("axios-retry");
|
|
3
|
+
|
|
4
|
+
const API_TIMEOUT = 3000;
|
|
5
|
+
const CONTENT_STACK_DELIVERY_URL = "https://cdn.contentstack.io/v3/";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const deliveryAxios = ({ apiKey, deliveryToken }) => {
|
|
9
|
+
const axiosClient = axios.create({
|
|
10
|
+
baseURL: CONTENT_STACK_DELIVERY_URL,
|
|
11
|
+
timeout: API_TIMEOUT,
|
|
12
|
+
headers: {
|
|
13
|
+
api_key: apiKey,
|
|
14
|
+
access_token: deliveryToken
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/* istanbul ignore next */
|
|
19
|
+
axiosRetry(axiosClient, {
|
|
20
|
+
retries: 3,
|
|
21
|
+
shouldResetTimeout: true,
|
|
22
|
+
retryCondition: () => true
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return axiosClient;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
deliveryAxios
|
|
30
|
+
};
|
package/src/csProduct.js
CHANGED
|
@@ -1,187 +1,354 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
3
|
+
const helpers = require('./helpers')
|
|
4
|
+
const { getProductStatus } = require('./status')
|
|
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 = (config) => {
|
|
12
|
+
if (!config) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`This will not work without a valid configuration {apiKey, environment, deliveryToken}.`
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { apiKey, environment, deliveryToken } = config
|
|
19
|
+
if (!apiKey) throw new Error('apiKey missing in config.')
|
|
20
|
+
else if (!environment) throw new Error('environment missing in config.')
|
|
21
|
+
else if (!deliveryToken) throw new Error('deliveryToken missing in config.')
|
|
22
|
+
}
|
|
6
23
|
|
|
7
24
|
const csProduct = (config) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const PRODUCT_TYPE = 'product';
|
|
25
|
+
const DEV_ENVIRONMENT = 'public-dev'
|
|
26
|
+
const VARIANTS = 'variants'
|
|
27
|
+
const KEY_INGREDIENTS = 'ingredients.key_ingredients'
|
|
28
|
+
const PRODUCT_HIGHLIGHTS = 'product_details.highlights'
|
|
29
|
+
const VARIANT_HIGHLIGHTS = 'variants.product_details.highlights'
|
|
30
|
+
const VARIANT_KEY_INGREDIENTS =
|
|
31
|
+
'variants.ingredients_override.key_ingredients'
|
|
32
|
+
const PRODUCT_FAQS = 'faqs'
|
|
33
|
+
const VARIANT_FAQS = 'variants.faqs'
|
|
34
|
+
const PRODUCT_RESOURCES = 'resources'
|
|
35
|
+
const VARIANT_RESOURCES = 'variants.resources'
|
|
36
|
+
const PRODUCT_CATEGORY = 'categories'
|
|
37
|
+
const PRODUCT_SUBCATEGORIES = 'categories.subcategories'
|
|
38
|
+
const DEFAULT_LOCALE = 'en'
|
|
39
|
+
const PRODUCT_TYPE = 'product'
|
|
40
|
+
const INCLUDE_FALLBACK = '&include_fallback=true'
|
|
41
|
+
const REQUIRED = 'required_products.product.'
|
|
42
|
+
const OPTIONAL = 'optional_products.product.'
|
|
43
|
+
const BUNDLE_TYPE = 'bundle'
|
|
28
44
|
|
|
29
45
|
// eslint-disable-next-line max-len
|
|
30
|
-
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}
|
|
46
|
+
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}`
|
|
47
|
+
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}`
|
|
48
|
+
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}`
|
|
31
49
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
apiKey = config.apiKey
|
|
36
|
-
environment = config.environment
|
|
37
|
-
deliveryToken = config.deliveryToken
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const deliveryAxios = axios.create({
|
|
41
|
-
baseURL: CONTENT_STACK_DELIVERY_URL,
|
|
42
|
-
timeout: 3000,
|
|
43
|
-
headers: {
|
|
44
|
-
api_key: apiKey,
|
|
45
|
-
access_token: deliveryToken
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
axiosRetry(deliveryAxios, {
|
|
49
|
-
retries: 3,
|
|
50
|
-
shouldResetTimeout: true,
|
|
51
|
-
// eslint-disable-next-line no-unused-vars
|
|
52
|
-
retryCondition: (_error) => true
|
|
53
|
-
});
|
|
50
|
+
validateConfig(config)
|
|
51
|
+
const { apiKey, environment, deliveryToken } = config
|
|
52
|
+
const axios = deliveryAxios({ apiKey, deliveryToken })
|
|
54
53
|
|
|
55
54
|
const asObject = () => {
|
|
56
|
-
return {apiKey, environment, deliveryToken}
|
|
55
|
+
return { apiKey, environment, deliveryToken }
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
const removeInvalidVariants = async (products, locale, translations) => {
|
|
59
|
+
const validSkus = []
|
|
60
|
+
for (const product of products) {
|
|
61
|
+
for (const variant of product?.variants || []) {
|
|
62
|
+
const bestSkuData = helpers?.getBestSkuData(variant) || []
|
|
63
|
+
if (bestSkuData && Object.keys(bestSkuData)?.length > 0) {
|
|
64
|
+
validSkus.push(bestSkuData.sku)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
if (environment === 'public-dev' && validSkus?.length === 0) return
|
|
69
|
+
|
|
70
|
+
const localeData = helpers?.parseLocale(locale)
|
|
71
|
+
locale = helpers?.reorderLocale(locale)
|
|
72
|
+
let status = {}
|
|
73
|
+
let marketData = {}
|
|
74
|
+
if (validSkus?.length > 0) {
|
|
75
|
+
status = await getProductStatus(validSkus, locale)
|
|
76
|
+
const localeSplit = locale.split('_')
|
|
77
|
+
let market =
|
|
78
|
+
localeSplit?.length > 1 ? localeSplit[1].toUpperCase() : 'XX'
|
|
79
|
+
if (market === 'XX') {
|
|
80
|
+
const split2 = locale.split('-')
|
|
81
|
+
market = split2.length > 1 ? split2[0].toUpperCase() : ''
|
|
82
|
+
}
|
|
83
|
+
marketData = await getEntriesByQuery({
|
|
84
|
+
contentType: 'market',
|
|
85
|
+
query: `{"iso_code_2": "${market}"}`,
|
|
86
|
+
locale: 'en'
|
|
87
|
+
})
|
|
88
|
+
if (marketData?.length > 0) {
|
|
89
|
+
marketData = marketData[0]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const product of products) {
|
|
93
|
+
const validVariants = []
|
|
94
|
+
for (const variant of product?.variants || []) {
|
|
95
|
+
const bestSkuData = helpers?.getBestSkuData(variant)
|
|
96
|
+
if (bestSkuData.sku) {
|
|
97
|
+
const varStatus = status[bestSkuData.sku]
|
|
98
|
+
if (varStatus && varStatus.status.retail) {
|
|
99
|
+
variant.sap_data.sku_data = [bestSkuData]
|
|
100
|
+
validVariants.push({
|
|
101
|
+
...variant,
|
|
102
|
+
status: varStatus,
|
|
103
|
+
marketData
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
product.variants = validVariants
|
|
109
|
+
product.translations = Array.isArray(translations)
|
|
110
|
+
? translations[0]
|
|
111
|
+
: translations
|
|
112
|
+
product.localeData = localeData
|
|
75
113
|
}
|
|
76
114
|
}
|
|
77
115
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
116
|
+
const parseSharedStrings = async (translations) => {
|
|
117
|
+
if (helpers?.isIterable(translations)) {
|
|
118
|
+
for (const translation of translations) {
|
|
119
|
+
translation.common_strings = translation?.common_strings
|
|
120
|
+
?.map((obj) => {
|
|
121
|
+
const commonStrings = { type: obj.key }
|
|
122
|
+
// eslint-disable-next-line no-sequences
|
|
123
|
+
commonStrings.strings = (
|
|
124
|
+
(obj || {}).strings || []
|
|
125
|
+
).reduce(
|
|
126
|
+
(result, { key, value }) => (
|
|
127
|
+
(result[key] = value), result
|
|
128
|
+
),
|
|
129
|
+
{}
|
|
130
|
+
)
|
|
131
|
+
return commonStrings
|
|
132
|
+
})
|
|
133
|
+
.reduce((result, { type, strings }) => {
|
|
134
|
+
result[type] = strings
|
|
135
|
+
return result
|
|
136
|
+
}, {})
|
|
137
|
+
}
|
|
94
138
|
}
|
|
95
139
|
}
|
|
96
|
-
|
|
140
|
+
|
|
141
|
+
const formatProductWithSchima = (products = []) => {
|
|
142
|
+
return products?.map((product) => {
|
|
143
|
+
const formatedProduct = formatProduct(product)
|
|
144
|
+
formatedProduct.variants = formatedProduct?.variants?.map(
|
|
145
|
+
(variant) => formatVariant(variant)
|
|
146
|
+
)
|
|
147
|
+
return formatedProduct
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const formatBundleWithSchima = (products = []) => {
|
|
152
|
+
return products?.map((product) => {
|
|
153
|
+
const formatedProduct = transformBundle(product)
|
|
154
|
+
formatedProduct.variants = formatedProduct?.variants?.map(
|
|
155
|
+
(variant) => formatVariant(variant)
|
|
156
|
+
)
|
|
157
|
+
return formatedProduct
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
97
161
|
// includes is an array of all the referenced types in the contentType you are requesting that should be resolved
|
|
98
162
|
// and returned (Example: ['common_strings'])
|
|
99
163
|
const getEntriesByQuery = async ({
|
|
100
|
-
contentType = PRODUCT_TYPE,
|
|
164
|
+
contentType = PRODUCT_TYPE,
|
|
165
|
+
query = '',
|
|
166
|
+
locale = DEFAULT_LOCALE,
|
|
167
|
+
includes,
|
|
168
|
+
start = 0,
|
|
169
|
+
limit = 50
|
|
101
170
|
}) => {
|
|
102
171
|
// eslint-disable-next-line max-len
|
|
103
172
|
let url = `content_types/${contentType}/entries?environment=${environment}&locale=${locale}&include_count=true&limit=${limit}&query=${query}`
|
|
104
173
|
if (contentType === PRODUCT_TYPE) {
|
|
105
174
|
url += productIncludes
|
|
106
175
|
}
|
|
176
|
+
if (contentType === BUNDLE_TYPE) {
|
|
177
|
+
url += requiredIncludes
|
|
178
|
+
url += optionalIncludes
|
|
179
|
+
}
|
|
107
180
|
if (includes) {
|
|
108
181
|
for (const include of includes) {
|
|
109
182
|
url += `&include[]=${include}`
|
|
110
183
|
}
|
|
111
184
|
}
|
|
112
|
-
if (environment === DEV_ENVIRONMENT){
|
|
113
|
-
url +=
|
|
185
|
+
if (environment === DEV_ENVIRONMENT) {
|
|
186
|
+
url += INCLUDE_FALLBACK
|
|
114
187
|
}
|
|
115
188
|
if (start > 0) {
|
|
116
189
|
url += `&skip=${start}`
|
|
117
190
|
}
|
|
118
191
|
try {
|
|
119
|
-
const res = await
|
|
120
|
-
|
|
121
|
-
return res && res.data && res.data.entries ? res.data.entries : res;
|
|
122
|
-
}
|
|
123
|
-
return res && res.data && res.data.entries ? res.data : res;
|
|
192
|
+
const res = await axios(url)
|
|
193
|
+
return res?.data?.entries ? res.data.entries : res
|
|
124
194
|
} catch (error) {
|
|
125
|
-
|
|
126
|
-
return error;
|
|
195
|
+
return error
|
|
127
196
|
}
|
|
128
197
|
}
|
|
129
198
|
|
|
130
|
-
const queryProducts = async(query, locale) => {
|
|
131
|
-
const products = await getEntriesByQuery({query, locale})
|
|
199
|
+
const queryProducts = async (query, locale) => {
|
|
200
|
+
const products = await getEntriesByQuery({ query, locale })
|
|
132
201
|
return products
|
|
133
202
|
}
|
|
134
203
|
|
|
204
|
+
const getBundle = async (id, locale) => {
|
|
205
|
+
const query = `{ "$or": [{ "bundle_id": { "$in": ["${id}"]}}, { "uid": { "$in": ["${id}"] }}] }`
|
|
206
|
+
const bundles = await getEntriesByQuery({
|
|
207
|
+
query,
|
|
208
|
+
locale,
|
|
209
|
+
contentType: BUNDLE_TYPE
|
|
210
|
+
})
|
|
211
|
+
const translations = await getTranslations(locale)
|
|
212
|
+
|
|
213
|
+
for (let b = 0; b < bundles.length; b++) {
|
|
214
|
+
for (
|
|
215
|
+
let i = 0;
|
|
216
|
+
i < (bundles[b].required_products || []).length;
|
|
217
|
+
i++
|
|
218
|
+
) {
|
|
219
|
+
await removeInvalidVariants(
|
|
220
|
+
bundles[b].required_products[i].product,
|
|
221
|
+
locale,
|
|
222
|
+
translations
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
for (
|
|
226
|
+
let i = 0;
|
|
227
|
+
i < (bundles[b].optional_products || []).length;
|
|
228
|
+
i++
|
|
229
|
+
) {
|
|
230
|
+
await removeInvalidVariants(
|
|
231
|
+
bundles[b].optional_products[i].product,
|
|
232
|
+
locale,
|
|
233
|
+
translations
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return formatBundleWithSchima(bundles)
|
|
238
|
+
}
|
|
239
|
+
|
|
135
240
|
const getProductsBySku = async (skus, locale) => {
|
|
136
241
|
if (!Array.isArray(skus)) {
|
|
137
242
|
skus = [skus]
|
|
138
243
|
}
|
|
139
|
-
const query = `{"variants": {"$in_query":{"sap_data.skus": {"$in": ${arrayString(
|
|
140
|
-
|
|
244
|
+
const query = `{"variants": {"$in_query":{"sap_data.skus": {"$in": ${helpers?.arrayString(
|
|
245
|
+
[skus]
|
|
246
|
+
)}}}}}`
|
|
247
|
+
|
|
248
|
+
let products = await queryProducts(query, locale)
|
|
249
|
+
const translations = await getTranslations(locale)
|
|
250
|
+
// await parseSharedStrings(translations);
|
|
251
|
+
await removeInvalidVariants(products, locale, translations)
|
|
252
|
+
return formatProductWithSchima(products)
|
|
141
253
|
}
|
|
142
254
|
|
|
143
255
|
const getProductsByGlobalId = async (ids, locale) => {
|
|
144
256
|
if (!Array.isArray(ids)) {
|
|
145
257
|
ids = [ids]
|
|
146
258
|
}
|
|
147
|
-
const query = `{"variants": {"$in_query":{"sap_data.global_id": {"$in": ${arrayString(
|
|
148
|
-
|
|
259
|
+
const query = `{"variants": {"$in_query":{"sap_data.global_id": {"$in": ${helpers?.arrayString(
|
|
260
|
+
[ids]
|
|
261
|
+
)}}}}}`
|
|
262
|
+
|
|
263
|
+
let products = await queryProducts(query, locale)
|
|
264
|
+
const translations = await getTranslations(locale)
|
|
265
|
+
// await parseSharedStrings(translations);
|
|
266
|
+
await removeInvalidVariants(products, locale, translations)
|
|
267
|
+
return formatProductWithSchima(products)
|
|
149
268
|
}
|
|
150
269
|
|
|
151
270
|
const getProductsBySlug = async (slugs, locale) => {
|
|
152
271
|
if (!Array.isArray(slugs)) {
|
|
153
272
|
slugs = [slugs]
|
|
154
273
|
}
|
|
155
|
-
const query = `{"seo_information.slug": {"$in": ${arrayString(
|
|
156
|
-
|
|
274
|
+
const query = `{"seo_information.slug": {"$in": ${helpers?.arrayString(
|
|
275
|
+
slugs
|
|
276
|
+
)}}}`
|
|
277
|
+
|
|
278
|
+
const products = await queryProducts(query, locale)
|
|
279
|
+
const translations = await getTranslations(locale)
|
|
280
|
+
// await parseSharedStrings(translations);
|
|
281
|
+
await removeInvalidVariants(products, locale, translations)
|
|
282
|
+
return formatProductWithSchima(products)
|
|
157
283
|
}
|
|
158
284
|
|
|
159
285
|
const getProductsByUID = async (ids, locale) => {
|
|
160
286
|
if (!Array.isArray(ids)) {
|
|
161
287
|
ids = [ids]
|
|
162
288
|
}
|
|
163
|
-
const query = `{"uid": {"$in": ${arrayString(ids)}}}`
|
|
164
|
-
|
|
289
|
+
const query = `{"uid": {"$in": ${helpers?.arrayString(ids)}}}`
|
|
290
|
+
let products = await queryProducts(query, locale)
|
|
291
|
+
const translations = await getTranslations(locale)
|
|
292
|
+
// await parseSharedStrings(translations);
|
|
293
|
+
await removeInvalidVariants(products, locale, translations)
|
|
294
|
+
return formatProductWithSchima(products)
|
|
165
295
|
}
|
|
166
296
|
|
|
167
297
|
const getTranslations = async (locale) => {
|
|
168
|
-
const translations = await getEntriesByQuery({
|
|
298
|
+
const translations = await getEntriesByQuery({
|
|
299
|
+
contentType: 'strings_product_detail_page',
|
|
300
|
+
locale,
|
|
301
|
+
includes: ['common_strings', 'subscriptions.modal']
|
|
302
|
+
})
|
|
303
|
+
await parseSharedStrings(translations)
|
|
169
304
|
return translations
|
|
170
305
|
}
|
|
171
306
|
|
|
307
|
+
const getProductTranslations = async (locale) => {
|
|
308
|
+
const translations = await getTranslations(locale)
|
|
309
|
+
const formatedTranslations = translations.map((translate) =>
|
|
310
|
+
formatTranslations(translate)
|
|
311
|
+
)
|
|
312
|
+
return formatedTranslations
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const publishedProducts = async ({ locale, skip = 0, limit = 50 } = {}) => {
|
|
316
|
+
let products =
|
|
317
|
+
(await getEntriesByQuery({
|
|
318
|
+
locale,
|
|
319
|
+
start: skip,
|
|
320
|
+
limit,
|
|
321
|
+
onlyEntries: false
|
|
322
|
+
})) || []
|
|
323
|
+
const count = products.count || 0
|
|
324
|
+
products = products.entries
|
|
325
|
+
const translations = await getTranslations(locale)
|
|
326
|
+
await parseSharedStrings(translations)
|
|
327
|
+
await removeInvalidVariants(products, locale, translations)
|
|
328
|
+
const transformProduct = formatProductWithSchima(products)
|
|
329
|
+
return {
|
|
330
|
+
products: transformProduct,
|
|
331
|
+
validCount: products.length,
|
|
332
|
+
totalCount: count,
|
|
333
|
+
skip
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
172
337
|
return {
|
|
173
338
|
asObject,
|
|
174
339
|
getEntriesByQuery,
|
|
175
340
|
getProductsBySku,
|
|
176
341
|
getProductsByGlobalId,
|
|
177
342
|
getProductsBySlug,
|
|
178
|
-
getProductsBySlugs,
|
|
179
|
-
getProductsByQuery,
|
|
180
343
|
getProductsByUID,
|
|
181
|
-
getTranslations
|
|
344
|
+
getTranslations,
|
|
345
|
+
publishedProducts,
|
|
346
|
+
formatTranslations,
|
|
347
|
+
getProductTranslations,
|
|
348
|
+
getBundle
|
|
182
349
|
}
|
|
183
350
|
}
|
|
184
351
|
|
|
185
352
|
module.exports = {
|
|
186
353
|
csProduct
|
|
187
|
-
}
|
|
354
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const helpers = require('./helpers')
|
|
2
|
+
const entities = require('entities')
|
|
3
|
+
|
|
4
|
+
/* istanbul ignore next */
|
|
5
|
+
const formatProduct = (parent) => ({
|
|
6
|
+
// Each value is a function with a parameter 'parent' that is the current instance of a Product
|
|
7
|
+
// ContentStack references need to be queried separately (ie: variants)
|
|
8
|
+
id: parent.uid,
|
|
9
|
+
slug: parent?.seo_information?.slug,
|
|
10
|
+
variantSelectLabel: parent.variant_select_label,
|
|
11
|
+
secondaryTitle: (parent) => parent.secondary_title,
|
|
12
|
+
title: parent.name,
|
|
13
|
+
productImages: helpers?.getProductImages(parent),
|
|
14
|
+
salesLabel: parent.sales_label,
|
|
15
|
+
salesText: parent.sales_text,
|
|
16
|
+
description: entities.decodeHTML(parent.short_description || ''),
|
|
17
|
+
salesDisclaimer: helpers?.mapSalesDisclaimer(parent.sales_disclaimer),
|
|
18
|
+
features: helpers?.mapFeatures(parent),
|
|
19
|
+
productDetails: helpers?.mapProductDetails(parent),
|
|
20
|
+
benefitsMedia: {
|
|
21
|
+
image: helpers?.mapImage(parent.benefits_media?.image),
|
|
22
|
+
youTubeVideoId: parent.benefits_media?.youtube_video_id
|
|
23
|
+
},
|
|
24
|
+
benefits: helpers?.mapBenefits(parent),
|
|
25
|
+
benefitsAndFeatures: helpers?.mapBenefitsAndFeatures(parent),
|
|
26
|
+
results: helpers?.mapResults(parent),
|
|
27
|
+
sustainability: helpers?.mapSustainability(parent),
|
|
28
|
+
usage: helpers?.mapUsage(parent, parent.legacy_usage),
|
|
29
|
+
resources: helpers?.mapResources(parent),
|
|
30
|
+
faqs: parent.faqs?.map((faq) => ({
|
|
31
|
+
question: faq.question,
|
|
32
|
+
answers: faq.answer || []
|
|
33
|
+
})),
|
|
34
|
+
categories: parent.categories?.map((category) => ({
|
|
35
|
+
displayName: category.display_name,
|
|
36
|
+
id: category.category_id,
|
|
37
|
+
subcategories: category.subcategories?.map((subcategory) => ({
|
|
38
|
+
displayName: subcategory.display_name,
|
|
39
|
+
id: subcategory.category_id
|
|
40
|
+
}))
|
|
41
|
+
})),
|
|
42
|
+
ingredients: helpers?.mapIngredients(
|
|
43
|
+
parent.ingredients,
|
|
44
|
+
parent.legacy_ingredients
|
|
45
|
+
),
|
|
46
|
+
legacyBenefits: parent.legacy_benefits,
|
|
47
|
+
legacyLongDescription: parent.legacy_long_description,
|
|
48
|
+
legacyResources: parent.legacy_resources,
|
|
49
|
+
legacyUsage: parent.legacy_usage,
|
|
50
|
+
legacyIngredients: parent.legacy_ingredients,
|
|
51
|
+
legacyImages: parent.legacy_images || [],
|
|
52
|
+
legacyYouTube: parent.legacy_youtube_video,
|
|
53
|
+
disclaimers: parent.disclaimers || [],
|
|
54
|
+
disclaimerWarnings: helpers?.mapDisclaimerWarnings(
|
|
55
|
+
parent.disclaimer_warnings
|
|
56
|
+
),
|
|
57
|
+
seoInformation: helpers?.mapSeoInformation(parent),
|
|
58
|
+
variants: helpers?.mapVariants(parent),
|
|
59
|
+
refund: helpers?.mapRefund(parent),
|
|
60
|
+
shipping: helpers?.mapShipping(parent),
|
|
61
|
+
generalDisclaimer: parent.translations?.general_disclaimer_text,
|
|
62
|
+
thirdPartyScripts: parent.third_party_scripts
|
|
63
|
+
?.filter((tps) => tps.enabled && !!tps.script)
|
|
64
|
+
?.map((tps) => tps.script),
|
|
65
|
+
csAtts: {
|
|
66
|
+
version: parent._version || 0,
|
|
67
|
+
updatedAt: parent.updated_at || '',
|
|
68
|
+
updatedBy: parent.updated_by || '',
|
|
69
|
+
createdAt: parent.created_at || '',
|
|
70
|
+
createdBy: parent.created_by || '',
|
|
71
|
+
locale: parent.locale || ''
|
|
72
|
+
},
|
|
73
|
+
relevancyRank: parent.relevancy_rank || null,
|
|
74
|
+
warranty: (parent) => helpers?.mapWarranty(parent),
|
|
75
|
+
upSellProductIds: (parent) => helpers?.mapUpSellProductIds(parent),
|
|
76
|
+
crossProductIds: (parent) => helpers?.mapCrossProductIds(parent)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
formatProduct
|
|
81
|
+
}
|