@nuskin/cs-product-lib 1.0.5 → 1.0.6-cx12-6632.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/cs-product-lib",
3
- "version": "1.0.5",
3
+ "version": "1.0.6-cx12-6632.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": {
@@ -43,6 +43,7 @@
43
43
  "config": "^3.3.6",
44
44
  "entities": "4.4.0",
45
45
  "lodash": "4.17.21",
46
+ "moment": "^2.29.4",
46
47
  "turndown": "7.1.1"
47
48
  }
48
49
  }
package/src/csProduct.js CHANGED
@@ -53,11 +53,14 @@ const csProduct = (props) => {
53
53
  const REQUIRED = 'required_products.product.'
54
54
  const OPTIONAL = 'optional_products.product.'
55
55
  const BUNDLE_TYPE = 'bundle'
56
+ const PRODUCT_BUNDLE = 'product_bundle'
56
57
 
57
58
  // 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 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}&include[]=${PRODUCT_BUNDLE}`
59
60
  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
61
  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}`
62
+ const bundleRequiredIncludes = `&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_FAQS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_FAQS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_CATEGORY}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_SUBCATEGORIES}`
63
+ const bundlOptionalIncludes = `&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_FAQS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_FAQS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_CATEGORY}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_SUBCATEGORIES}`
61
64
 
62
65
  validateConfig(props)
63
66
  const { apiKey, environment, deliveryToken, homeUrl, awsBase, clientId } = props
@@ -183,6 +186,45 @@ const csProduct = (props) => {
183
186
  })
184
187
  }
185
188
 
189
+ const formatBundleKit = async (products, locale, translations) => {
190
+ for (let p = 0; p < products.length; p++) {
191
+ for (let b = 0; b < products[p]?.product_bundle?.length || 0; b++) {
192
+
193
+ for (
194
+ let i = 0;
195
+ i < (products[p].product_bundle[b].required_products || []).length;
196
+ i++
197
+ ) {
198
+ await removeInvalidVariants(
199
+ products[p].product_bundle[b].required_products[i].product,
200
+ locale,
201
+ translations
202
+ )
203
+ }
204
+ for (
205
+ let i = 0;
206
+ i < (products[p].product_bundle[b].optional_products || []).length;
207
+ i++
208
+ ) {
209
+ await removeInvalidVariants(
210
+ products[p].product_bundle[b].optional_products[i].product,
211
+ locale,
212
+ translations
213
+ )
214
+ }
215
+ products[p].product_bundle[b].type = "bundle"
216
+ }
217
+ products[p].bundle = formatBundleWithSchema(products[p].product_bundle)
218
+ if(products[p].product_bundle?.length > 0){
219
+ products[p].variants = []
220
+ }
221
+ products[p].type = (products[p].product_bundle?.length || 0) > 0 ? "bundle" : null
222
+ delete products[p].product_bundle
223
+
224
+
225
+ }
226
+ }
227
+
186
228
  // includes is an array of all the referenced types in the contentType you are requesting that should be resolved
187
229
  // and returned (Example: ['common_strings'])
188
230
  const getEntriesByQuery = async ({
@@ -198,6 +240,8 @@ const csProduct = (props) => {
198
240
  let url = `content_types/${contentType}/entries?environment=${environment}&locale=${locale}&include_count=true&limit=${limit}&query=${query}`
199
241
  if (contentType === PRODUCT_TYPE) {
200
242
  url += productIncludes
243
+ url += bundleRequiredIncludes
244
+ url += bundlOptionalIncludes
201
245
  }
202
246
  if (contentType === BUNDLE_TYPE) {
203
247
  url += requiredIncludes
@@ -312,7 +356,7 @@ const csProduct = (props) => {
312
356
 
313
357
  let products = await queryProducts(query, locale)
314
358
  const translations = await getTranslations(locale)
315
- // await parseSharedStrings(translations);
359
+ await formatBundleKit(products, locale, translations)
316
360
  await removeInvalidVariants(products, locale, translations)
317
361
  for (const product of products) {
318
362
  product.skus = skus
@@ -331,7 +375,7 @@ const csProduct = (props) => {
331
375
 
332
376
  let products = await queryProducts(query, locale)
333
377
  const translations = await getTranslations(locale)
334
- // await parseSharedStrings(translations);
378
+ await formatBundleKit(products, locale, translations)
335
379
  await removeInvalidVariants(products, locale, translations)
336
380
  return formatProductWithSchema(products)
337
381
  }
@@ -346,7 +390,7 @@ const csProduct = (props) => {
346
390
 
347
391
  const products = await queryProducts(query, locale)
348
392
  const translations = await getTranslations(locale)
349
- // await parseSharedStrings(translations);
393
+ await formatBundleKit(products, locale, translations)
350
394
  await removeInvalidVariants(products, locale, translations)
351
395
  return formatProductWithSchema(products)
352
396
  }
@@ -358,7 +402,7 @@ const csProduct = (props) => {
358
402
  const query = `{"uid": {"$in": ${helpers?.arrayString(ids)}}}`
359
403
  let products = await queryProducts(query, locale)
360
404
  const translations = await getTranslations(locale)
361
- // await parseSharedStrings(translations);
405
+ await formatBundleKit(products, locale, translations)
362
406
  await removeInvalidVariants(products, locale, translations)
363
407
  return formatProductWithSchema(products)
364
408
  }
@@ -0,0 +1,169 @@
1
+ const moment = require('moment')
2
+
3
+ const parseStatus = (variant) => {
4
+ const dateFormat = 'YYYY-MM-DD'
5
+ const properties = variant.properties || {}
6
+ if (
7
+ variant.inventoryProperties &&
8
+ variant.inventoryProperties.backOrdered &&
9
+ variant.inventoryProperties.expectedBackOrderAvailabilityDate) {
10
+ return {
11
+
12
+ // changed
13
+ status: 'inactive',
14
+ isBackordered: variant.inventoryProperties.backOrdered,
15
+ backorderedAvailableDate: moment(variant.inventoryProperties.expectedBackOrderAvailabilityDate).format(dateFormat)
16
+ }
17
+ } else if(properties.productStatus) {
18
+ let isBackordered = false
19
+ let backorderedAvailableDate = null
20
+ if (variant.skuKit) {
21
+ try {
22
+ const latestBODate = Math.min(...variant.skuKit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.expectedBackOrderAvailabilityDate))) || 0
23
+ if (latestBODate) {
24
+ isBackordered = true
25
+ backorderedAvailableDate = moment(Date(latestBODate)).format(dateFormat)
26
+ }
27
+ } catch {
28
+ backorderedAvailableDate = null
29
+ }
30
+
31
+ } else if (variant.bundle) {
32
+ try {
33
+ const latestBODate = Math.min(...variant.bundleMandatoryProducts.flatMap(a=>a.sku.map(s=>s.inventoryProperties.expectedBackOrderAvailabilityDate))) || 0
34
+ if (latestBODate) {
35
+ isBackordered = true
36
+ backorderedAvailableDate = moment(Date(latestBODate)).format(dateFormat)
37
+ }
38
+ } catch {
39
+ backorderedAvailableDate = null
40
+ }
41
+ }
42
+ return {
43
+ // changed
44
+ status: 'active',
45
+ isBackordered,
46
+ backorderedAvailableDate
47
+ }
48
+ }
49
+ return {
50
+ // changed
51
+ status: 'active',
52
+ isBackordered: false,
53
+ backorderedAvailableDate: null
54
+ }
55
+ };
56
+
57
+ const parsePrice = (variant) => {
58
+ const price = {}
59
+ const points = {}
60
+ price.currencyCode = (variant.prices || [])?.[0]?.currencyCode || (variant?.prices || [])?.[0]?.currencySymbol
61
+ const priceFacets = variant?.priceFacets || {}
62
+ price.retail = priceFacets['Regular Price'] || ((variant?.prices || [])[0] || {}).price
63
+ price.wholesale = priceFacets['Wholesale Price'] || ((variant?.prices || [])[0] || {}).price
64
+ price.retailSubscription = priceFacets['Regular Price'] || ((variant?.prices || [])[0] || {}).price
65
+ price.wholesaleSubscription = priceFacets['Wholesale Price'] || ((variant?.prices || [])[0] || {}).price
66
+ points.wholesale = {cv: priceFacets.CV, pv: priceFacets.PV, sb: priceFacets.SB}
67
+ // Where do we pull subscription price/points from?
68
+ points.subscription = {cv: priceFacets.CV, pv: priceFacets.PV, sb: priceFacets.SB}
69
+ return {price, points}
70
+ }
71
+
72
+ const parseKitAvailableQuantity = (skuKit) => {
73
+ try {
74
+ return Math.min(...skuKit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.atpQty))) || 0
75
+ } catch {
76
+ return 0
77
+ }
78
+ }
79
+
80
+ const parseBundleAvailableQuantity = (product) => {
81
+ try {
82
+ const {requiredProducts = []} = product|| {}
83
+ const quantities = requiredProducts?.map(p => p?.quantity || 0)
84
+ return Math.min(...quantities) || 0
85
+ } catch {
86
+ console.log("some error in availableQuantity")
87
+ return 0
88
+ }
89
+ }
90
+
91
+ const parseKit = (product, market) => {
92
+ const kits = {}
93
+ const [properties] = product || []
94
+ kits.description = properties?.description
95
+ kits.availableChannels = properties.availableChannels
96
+ kits.chargeShipping = properties.chargeShipping === 'true'
97
+ kits.customerTypes = properties.customerTypes
98
+ kits.dangerousGoods = properties.dangerousGoods === 'true'
99
+ // missing
100
+ kits.excludeFromSearch = properties.excludeFromSearch === 'true'
101
+ kits.isExclusive = properties.isExclusive === 'true'
102
+ kits.marketAttributes = properties?.marketAttributes
103
+ kits.maxQuantity = (product.inventoryProperties || {}).atpQty
104
+ const priceData = parsePrice(product)
105
+ kits.points = priceData?.points
106
+ kits.price = priceData?.price
107
+ kits.purchaseTypes = {
108
+ buyOnce: kits?.availableChannels?.includes('web'),
109
+ subscription: kits?.availableChannels?.includes('subscription')
110
+ }
111
+ kits.retailDiscount= properties?.retailDiscount
112
+ kits.wholesaleDiscount = properties?.wholesaleDiscount
113
+ kits.pvDiscount = properties?.pvDiscount
114
+ kits.cvDiscount = properties?.cvDiscount
115
+ kits.sbDiscount = properties?.sbDiscount
116
+ kits.grpDiscount = properties?.grpDiscount
117
+ kits.scanQualifiedCount = properties?.scanQualifiedCount
118
+ // newVariant.slug = undefined
119
+ kits.status = parseStatus(product)
120
+ if ((kits.status || {}).status === 'active') kits.status.status = 'sellable'
121
+ const kitProducts = []
122
+ if (properties.type === 'kit') {
123
+ kits.type = 'skuKit'
124
+ kits.availableQuantity = parseKitAvailableQuantity(product.skuKit)
125
+ for (const kit of product.skuKit) {
126
+ const kitProduct = formatKit(kit, market)
127
+ kitProduct.id = kit.identifier
128
+ kitProducts.push({product: kitProduct, quantity: (kit.properties || {}).quantity || 0, isMandatory:true})
129
+ }
130
+ } else if (properties.type === 'bundle') {
131
+ kits.type = 'bundle'
132
+ kits.availableQuantity = parseBundleAvailableQuantity(properties)
133
+ for (const kit of properties?.requiredProducts || []) {
134
+ const kitProduct = formatKit(kit?.product, market)
135
+ kitProduct.id = kit.product.id
136
+ kitProducts.push({product: kitProduct, quantity: kit?.quantity || 0, isMandatory:true})
137
+ }
138
+ for (const kit of properties?.optionalProducts || []) {
139
+ const kitProduct = formatKit(kit?.product, market)
140
+ kitProduct.id = kit.product.id
141
+ kitProducts.push({product: kitProduct, quantity: kit?.quantity || 0, isMandatory:false})
142
+ }
143
+ }
144
+ kits.kitProducts = kitProducts
145
+ return kits
146
+ }
147
+
148
+ const formatKit = (product, market) => {
149
+
150
+ if (!product) {
151
+ return {}
152
+ }
153
+
154
+ let kit = null
155
+ if(['kit', 'bundle'].includes(product.type)) {
156
+ kit = parseKit(product.bundle, market)
157
+ }
158
+ return {
159
+ ...product,
160
+ bundle: kit
161
+
162
+ }
163
+ }
164
+
165
+
166
+ module.exports = {
167
+ formatKit
168
+ }
169
+
@@ -1,77 +1,83 @@
1
1
  const helpers = require('./helpers')
2
2
  const entities = require('entities')
3
+ const { formatKit } = require('./formatKit')
3
4
 
4
5
  /* istanbul ignore next */
5
- const formatProduct = (parent, homeUrl) => ({
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.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: helpers?.mapFaqs(parent),
31
- categories: parent.categories?.map((category) => ({
32
- displayName: category.display_name,
33
- id: category.category_id,
34
- subcategories: category.subcategories?.map((subcategory) => ({
35
- displayName: subcategory.display_name,
36
- id: subcategory.category_id
37
- }))
38
- })),
39
- ingredients: helpers?.mapIngredients(
40
- parent.ingredients,
41
- parent.legacy_ingredients
42
- ),
43
- legacyBenefits: parent.legacy_benefits,
44
- legacyLongDescription: parent.legacy_long_description,
45
- legacyResources: parent.legacy_resources,
46
- legacyUsage: parent.legacy_usage,
47
- legacyIngredients: parent.legacy_ingredients,
48
- legacyImages: parent.legacy_images || [],
49
- legacyYouTube: parent.legacy_youtube_video,
50
- disclaimers: parent.disclaimers || [],
51
- disclaimerWarnings: helpers?.mapDisclaimerWarnings(
52
- parent.disclaimer_warnings
53
- ),
54
- seoInformation: helpers?.mapSeoInformation(parent, homeUrl),
55
- variants: helpers?.mapVariants(parent),
56
- refund: helpers?.mapRefund(parent),
57
- shipping: helpers?.mapShipping(parent),
58
- generalDisclaimer: parent.translations?.general_disclaimer_text,
59
- thirdPartyScripts: parent.third_party_scripts
60
- ?.filter((tps) => tps.enabled && !!tps.script)
61
- ?.map((tps) => tps.script),
62
- csAtts: {
63
- version: parent._version || 0,
64
- updatedAt: parent.updated_at || '',
65
- updatedBy: parent.updated_by || '',
66
- createdAt: parent.created_at || '',
67
- createdBy: parent.created_by || '',
68
- locale: parent.locale || ''
69
- },
70
- relevancyRank: parent.relevancy_rank || null,
71
- warranty: helpers?.mapWarranty(parent),
72
- upSellProductIds: helpers?.mapUpSellProductIds(parent),
73
- crossProductIds: helpers?.mapCrossProductIds(parent)
74
- })
6
+ const formatProduct = (parent, homeUrl) => {
7
+ const formatedProduct = {
8
+ // Each value is a function with a parameter 'parent' that is the current instance of a Product
9
+ // ContentStack references need to be queried separately (ie: variants)
10
+ id: parent.uid,
11
+ slug: parent?.seo_information?.slug,
12
+ variantSelectLabel: parent.variant_select_label,
13
+ secondaryTitle: parent.secondary_title,
14
+ title: parent.name,
15
+ productImages: helpers?.getProductImages(parent),
16
+ salesLabel: parent.sales_label,
17
+ salesText: parent.sales_text,
18
+ description: entities.decodeHTML(parent.short_description || ''),
19
+ salesDisclaimer: helpers?.mapSalesDisclaimer(parent.sales_disclaimer),
20
+ features: helpers?.mapFeatures(parent),
21
+ productDetails: helpers?.mapProductDetails(parent),
22
+ benefitsMedia: {
23
+ image: helpers?.mapImage(parent.benefits_media?.image),
24
+ youTubeVideoId: parent.benefits_media?.youtube_video_id
25
+ },
26
+ benefits: helpers?.mapBenefits(parent),
27
+ benefitsAndFeatures: helpers?.mapBenefitsAndFeatures(parent),
28
+ bundle: parent?.bundle,
29
+ type: parent?.type,
30
+ results: helpers?.mapResults(parent),
31
+ sustainability: helpers?.mapSustainability(parent),
32
+ usage: helpers?.mapUsage(parent, parent.legacy_usage),
33
+ resources: helpers?.mapResources(parent),
34
+ faqs: helpers?.mapFaqs(parent),
35
+ categories: parent.categories?.map((category) => ({
36
+ displayName: category.display_name,
37
+ id: category.category_id,
38
+ subcategories: category.subcategories?.map((subcategory) => ({
39
+ displayName: subcategory.display_name,
40
+ id: subcategory.category_id
41
+ }))
42
+ })),
43
+ ingredients: helpers?.mapIngredients(
44
+ parent.ingredients,
45
+ parent.legacy_ingredients
46
+ ),
47
+ legacyBenefits: parent.legacy_benefits,
48
+ legacyLongDescription: parent.legacy_long_description,
49
+ legacyResources: parent.legacy_resources,
50
+ legacyUsage: parent.legacy_usage,
51
+ legacyIngredients: parent.legacy_ingredients,
52
+ legacyImages: parent.legacy_images || [],
53
+ legacyYouTube: parent.legacy_youtube_video,
54
+ disclaimers: parent.disclaimers || [],
55
+ disclaimerWarnings: helpers?.mapDisclaimerWarnings(
56
+ parent.disclaimer_warnings
57
+ ),
58
+ seoInformation: helpers?.mapSeoInformation(parent, homeUrl),
59
+ variants: helpers?.mapVariants(parent),
60
+ refund: helpers?.mapRefund(parent),
61
+ shipping: helpers?.mapShipping(parent),
62
+ generalDisclaimer: parent.translations?.general_disclaimer_text,
63
+ thirdPartyScripts: parent.third_party_scripts
64
+ ?.filter((tps) => tps.enabled && !!tps.script)
65
+ ?.map((tps) => tps.script),
66
+ csAtts: {
67
+ version: parent._version || 0,
68
+ updatedAt: parent.updated_at || '',
69
+ updatedBy: parent.updated_by || '',
70
+ createdAt: parent.created_at || '',
71
+ createdBy: parent.created_by || '',
72
+ locale: parent.locale || ''
73
+ },
74
+ relevancyRank: parent.relevancy_rank || null,
75
+ warranty: helpers?.mapWarranty(parent),
76
+ upSellProductIds: helpers?.mapUpSellProductIds(parent),
77
+ crossProductIds: helpers?.mapCrossProductIds(parent)
78
+ }
79
+ return formatKit(formatedProduct)
80
+ }
75
81
 
76
82
  module.exports = {
77
83
  formatProduct
package/src/helpers.js CHANGED
@@ -21,7 +21,7 @@ function mapBrandStyle(feature, type) {
21
21
  const isBrandStyle = feature.brand_style && Array.isArray(feature.brand_style) && feature.brand_style.length > 0;
22
22
  // eslint-disable-next-line no-nested-ternary
23
23
  const backgroundColor = isBrandStyle ? feature.brand_style[0].background_color : feature.background_color.length > 1 ? feature.background_color : '#4f4d4d';
24
- const textColor = isBrandStyle && feature.brand_style[0].background_color.length > 0 ? '#000000' : '#ffffff';
24
+ const textColor = isBrandStyle && feature.brand_style[0].background_color?.length > 0 ? '#000000' : '#ffffff';
25
25
 
26
26
  switch (type) {
27
27
  case TEXT_COLOR:
@@ -30,7 +30,7 @@ function mapBrandStyle(feature, type) {
30
30
  }
31
31
  return textColor;
32
32
  case BACKGROUND_COLOR:
33
- if (!backgroundColor.includes('#')) {
33
+ if (!backgroundColor?.includes('#')) {
34
34
  return `#${backgroundColor}`
35
35
  }
36
36
  return backgroundColor;
@@ -313,7 +313,7 @@ function mapVariants(parent) {
313
313
  }
314
314
 
315
315
  function mapSeoInformation(parent, homeUrl) {
316
- const { ogImage } = parent.seo_information
316
+ const { ogImage } = parent?.seo_information || {}
317
317
  const seoData = {
318
318
  metaTitle: parent?.seo_information?.meta_title || parent.name,
319
319
  metaDescription:
@@ -5,6 +5,7 @@ const transformBundle = (parent, homeUrl) => ({
5
5
  id: parent.bundle_id,
6
6
  uid: parent.uid,
7
7
  title: parent.name,
8
+ type: parent.type,
8
9
  requiredProducts: parent.required_products?.map((r) => ({
9
10
  product: r?.product?.[0],
10
11
  quantity: r.quantity