@nuskin/cs-product-lib 1.3.0-td-688.1 → 1.3.1

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.3.0-td-688.1",
3
+ "version": "1.3.1",
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": {
package/src/csProduct.js CHANGED
@@ -10,8 +10,6 @@ const { transformBundle } = require('./transformBundle')
10
10
  const { formatCategoryTranslations } = require('./formatCategoryTranslations')
11
11
  const { isNullOrEmpty } = require('@nuskin/ns-common-lib')
12
12
  const { formatDiscounts } = require('./helpers/formatDiscounts');
13
- const { formatCategory } = require('./formatCategory')
14
- const { getAllTopCategories } = require('./getAllTopCategories')
15
13
 
16
14
  const validateConfig = (props) => {
17
15
  if (!props) {
@@ -57,16 +55,16 @@ const csProduct = (props) => {
57
55
  const PRODUCT_BRAND_STYLE = 'features.brand_style'
58
56
  const DEFAULT_LOCALE = 'en'
59
57
  const PRODUCT_TYPE = 'product'
60
- const CATEGORY_TYPE = 'category'
61
58
  const INCLUDE_FALLBACK = '&include_fallback=true'
62
59
  const REQUIRED = 'required_products.product.'
63
60
  const OPTIONAL = 'optional_products.product.'
64
61
  const BUNDLE_TYPE = 'bundle'
65
62
  const PRODUCT_BUNDLE = 'product_bundle'
66
63
  const PRODUCT_SKU_KIT = 'sku_kit'
64
+ const VARIANT_DISCONTINUED_SKU_REPLACEMENT = 'variants.discontinued_sku_replacement'
67
65
 
68
66
  // eslint-disable-next-line max-len
69
- 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}&include[]=${PRODUCT_SKU_KIT}`
67
+ 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}&include[]=${PRODUCT_SKU_KIT}&include[]=${VARIANT_DISCONTINUED_SKU_REPLACEMENT}`
70
68
  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}`
71
69
  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}`
72
70
  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}`
@@ -260,16 +258,16 @@ const csProduct = (props) => {
260
258
  }
261
259
  const products = await getProductsBySku(variantSkus, locale)
262
260
  const requiredProducts = []
263
- for (let i = 0; i < products.length; i++) {
261
+ for (let i = 0; i < products?.length; i++) {
264
262
  for (const variantSku of variantSkus) {
265
263
  const productSelect = JSON.parse(JSON.stringify(products[i]))
266
- for (let v = 0; v < productSelect.variants.length; v++) {
264
+ for (let v = 0; v < productSelect?.variants?.length; v++) {
267
265
  if (productSelect.variants[v].sku !== variantSku) {
268
266
  productSelect.variants.splice(v, 1)
269
267
  v--
270
268
  }
271
269
  }
272
- if (!isNullOrEmpty(productSelect.variants)) {
270
+ if (!isNullOrEmpty(productSelect?.variants)) {
273
271
  requiredProducts.push({
274
272
  product: [productSelect],
275
273
  quantity: skuKit[0].variants.find(v=>v.sku === variantSku).quantity
@@ -619,25 +617,6 @@ const csProduct = (props) => {
619
617
  }
620
618
  }
621
619
 
622
- const getCategoryById = async (id, locale) => {
623
- locale = badLocaleMap(locale)
624
- try {
625
- const categories = await getEntriesByQuery({
626
- contentType: CATEGORY_TYPE,
627
- query: `{"category_id": "${id}"}`,
628
- locale,
629
- includes: ['subcategories']
630
- })
631
- const { country, language } = helpers.parseLocale(locale)
632
- const allTopCategories = await getAllTopCategories(locale, environment)
633
- const category = categories[0]
634
- category.localeData = { country, language }
635
- return formatCategory(category, language, homeUrl, allTopCategories)
636
- } catch (error) {
637
- throw new Error('Failed to fetch category')
638
- }
639
- };
640
-
641
620
  return {
642
621
  asObject,
643
622
  getEntriesByQuery,
@@ -652,11 +631,10 @@ const csProduct = (props) => {
652
631
  getBundle,
653
632
  getBundles,
654
633
  getCategoryPageTranslations,
655
- formatProductWithSchema,
656
- getCategoryById
634
+ formatProductWithSchema
657
635
  }
658
636
  }
659
637
 
660
638
  module.exports = {
661
639
  csProduct
662
- }
640
+ }
@@ -7,6 +7,8 @@ const formatTranslations = (parent) => ({
7
7
  parent?.common_strings?.product?.addToCart,
8
8
  allIngredients: parent?.all_ingredients,
9
9
  otherIngredients: parent?.other_ingredients,
10
+ replacementTitle: parent?.pdp_replacementtitle,
11
+ itemDiscontinued: parent?.pdp_itemdiscontinued,
10
12
  activeIngredients: parent?.active_ingredients,
11
13
  inactiveIngredients: parent?.inactive_ingredients,
12
14
  benefitsAndKeyFeatures: parent?.benefits_and_key_features,
@@ -118,7 +118,8 @@ const formatVariant = (parent) => {
118
118
  channels: helpers?.getBestSkuData(parent)?.channels,
119
119
  foreignLimit: helpers?.getBestSkuData(parent)?.foreign_limit,
120
120
  foreignOrderLimit: helpers?.getBestSkuData(parent)?.foreign_limit,
121
- orderType: parent.sap_data?.order_type
121
+ orderType: parent.sap_data?.order_type,
122
+ discontinuedSkuReplacement: helpers?.mapDiscontinuedSkuReplacement(parent)?.sku
122
123
  }
123
124
  }
124
125
 
package/src/helpers.js CHANGED
@@ -348,15 +348,6 @@ function mapSeoInformation(parent, homeUrl, type) {
348
348
  parent?.seo_information?.slug
349
349
  }`
350
350
  break
351
- case 'nav-category':
352
- seoData.canonicalURL = `${homeUrl}/${
353
- parent?.localeData?.country
354
- }/${parent?.localeData?.language}/catalog/${
355
- parent?.category_id || parent?.seo_information?.slug
356
- }`
357
- seoData.metaTitle = seoData.metaTitle || parent?.display_name || '',
358
- seoData.metaDescription = seoData.metaDescription || ''
359
- break
360
351
  default:
361
352
  break
362
353
  }
@@ -1191,8 +1182,12 @@ function mapFaqs(product) {
1191
1182
  return []
1192
1183
  }
1193
1184
 
1194
- function isTopCategory(category, allTopCategories){
1195
- return Array.isArray(allTopCategories) && allTopCategories.some(cat => cat.id === category.category_id);
1185
+ function mapDiscontinuedSkuReplacement (product) {
1186
+ if (product?.discontinued_sku_replacement?.length > 0) {
1187
+ return getBestSkuData(product?.discontinued_sku_replacement[0])
1188
+ } else {
1189
+ return {}
1190
+ }
1196
1191
  }
1197
1192
 
1198
1193
  module.exports = {
@@ -1240,5 +1235,5 @@ module.exports = {
1240
1235
  createMarkdownFromRTE,
1241
1236
  benefitsToMarkdown,
1242
1237
  mapActiveEventDisclaimer,
1243
- isTopCategory
1238
+ mapDiscontinuedSkuReplacement
1244
1239
  }
@@ -1,32 +0,0 @@
1
- const helpers = require('./helpers');
2
-
3
- const formatSubcategory = (subcategory, index) => ({
4
- displayName: subcategory?.display_name || '',
5
- categoryIdentifier: subcategory?.category_id || '',
6
- sequence: index + 1
7
- });
8
-
9
- const formatProduct = (product) => ({
10
- title: product?.title || '',
11
- productID: product?.product_id || ''
12
- });
13
-
14
- const formatCategory = (parent, language = 'en', homeUrl, allTopCategories) => ({
15
- displayName: parent?.display_name || '',
16
- categoryIdentifier: parent?.category_id || '',
17
- status: parent?.status || 'Inactive',
18
- isHiddenFromNavigation: parent?.is_hidden_from_navigation || false,
19
- startTime: parent?.start_time || '1994-01-03T08:00:01.000Z',
20
- endTime: parent?.end_time || '2038-01-01T08:00:01.000Z',
21
- isTopCategory: helpers.isTopCategory(parent, allTopCategories),
22
- image: helpers.mapImage(parent?.image),
23
- description: parent?.description?.[0] || '',
24
- subcategories: parent?.subcategories?.map(formatSubcategory) || [],
25
- seoInformation: helpers.mapSeoInformation(parent, homeUrl, 'nav-category'),
26
- products: parent?.products?.map(formatProduct) || [],
27
- language
28
- });
29
-
30
- module.exports = {
31
- formatCategory
32
- };
@@ -1,48 +0,0 @@
1
- const axios = require("axios");
2
- const helpers = require('./helpers');
3
-
4
- const productApiMapping = {
5
- 'public-dev': 'https://product.api.dev.nuskin.com/graphql',
6
- 'public-prod': 'https://product.api.nuskin.com/graphql',
7
- 'public-test': 'https://product.api.test.nuskin.com/graphql'
8
- };
9
-
10
- const query = `
11
- query Categories($groupByCategory: Boolean, $language: String, $market: String) {
12
- categories(groupByCategory: $groupByCategory, language: $language, market: $market) {
13
- categories {
14
- id
15
- displayName
16
- }
17
- }
18
- }
19
- `;
20
-
21
- const getAllTopCategories = async (locale, environment) => {
22
- const productGraphqlUrl = productApiMapping[environment];
23
- if (!productGraphqlUrl) {
24
- throw new Error('Invalid environment');
25
- }
26
-
27
- const { country, language } = helpers.parseLocale(locale);
28
-
29
- try {
30
- const response = await axios.post(productGraphqlUrl, {
31
- operationName: "Categories",
32
- query,
33
- variables: {
34
- groupByCategory: true,
35
- market: country,
36
- language
37
- }
38
- });
39
-
40
- return response?.data?.data?.categories?.categories;
41
- } catch (error) {
42
- throw new Error('Failed to fetch all categories');
43
- }
44
- };
45
-
46
- module.exports = {
47
- getAllTopCategories
48
- };