@nuskin/product-components 3.18.0-cx24-6773.1 → 3.18.0-td-341.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.
@@ -6,6 +6,7 @@ import {
6
6
  import {
7
7
  events,
8
8
  StringService,
9
+ csStringService,
9
10
  util,
10
11
  SitesSessionStorageService,
11
12
  ShoppingContext,
@@ -21,12 +22,10 @@ import {
21
22
  AdrService,
22
23
  FavoritesService,
23
24
  ProductStatus,
24
- QualificationService as OldQualificationService,
25
25
  Product as ShopProduct,
26
26
  EquinoxCartService
27
27
  } from "@nuskin/ns-shop";
28
- import { default as NewQualificationService } from "@nuskin/exclusive-offer-sdk";
29
- import { retrieveTogglesBasedOnEnvironment } from "@nuskin/ns-feature-flags";
28
+ import QualificationService from "@nuskin/exclusive-offer-sdk";
30
29
  import webLoyalty from "@nuskin/ns-loyalty-web";
31
30
  import { getProp, getFullUrl } from "@nuskin/ns-common-lib";
32
31
  import { PriceType } from "@nuskin/ns-product-lib";
@@ -38,31 +37,6 @@ const PENDING_FAVORITE = "pendingFavorite";
38
37
  const KEY_BREADCRUMB_BACK = "breadcrumbBack";
39
38
  const BUNDLE = "BUNDLE";
40
39
 
41
- let flagsPromise = null;
42
- let featureFlags = false;
43
- const checkFlag = async flag => {
44
- if (!featureFlags && !flagsPromise) {
45
- flagsPromise = retrieveTogglesBasedOnEnvironment().then(
46
- flagsFromServer => (featureFlags = flagsFromServer)
47
- );
48
- }
49
-
50
- if (!featureFlags) {
51
- await flagsPromise;
52
- }
53
-
54
- return featureFlags.has(flag);
55
- };
56
-
57
- const getQualificationService = async () => {
58
- const equinoxMarket = (await getConfiguration(["Equinox_Markets"]))
59
- .Equinox_Markets;
60
- return equinoxMarket.active ||
61
- (await checkFlag("cx15_use_new_exclusive_offer_api"))
62
- ? NewQualificationService
63
- : OldQualificationService;
64
- };
65
-
66
40
  /**
67
41
  * NsProductMixin
68
42
  *
@@ -273,7 +247,11 @@ const NsProductMixin = {
273
247
  return this.$NsProductUserService.isPreferredCustomer;
274
248
  },
275
249
  isWholesale() {
276
- return this.$NsProductUserService.isWholesale;
250
+ if (this.$NsProductUserService.isLoggedIn) {
251
+ return this.$NsProductUserService.isUserWholesale;
252
+ } else {
253
+ return this.$NsProductUserService.isWholesale;
254
+ }
277
255
  },
278
256
  loyaltyStatusAndLinks() {
279
257
  return this.marketConfig.loyalty || {};
@@ -495,8 +473,32 @@ const NsProductMixin = {
495
473
  this.loyaltyStatusAndLinks.productOptedInRedeemNotEarn =
496
474
  "Save with Nu Skin Rewards";
497
475
 
498
- StringService.getApplicationStrings("loyalty").then(content => {
499
- this.loyaltyStrings = content;
476
+ const commonStringKeys = [
477
+ { key: "productDisplayNotOptedinMessage", dflt: "" },
478
+ {
479
+ key: "productDisplayOptedinMessage",
480
+ dflt: "{earnPercentage} Nu Skin enJoy Rewards Available!"
481
+ },
482
+ { key: "productOptedInEarnNotRedeem", dflt: "" },
483
+ {
484
+ key: "productOptedInRedeemNotEarn",
485
+ dflt:
486
+ "This product does not earn rewards points but is available to be redeemed for rewards points."
487
+ }
488
+ ];
489
+
490
+ try {
491
+ let loyalityStringsContent = {};
492
+ if (this.$NsProductAppService.useCSResources) {
493
+ loyalityStringsContent = await csStringService.getStrings(
494
+ commonStringKeys
495
+ );
496
+ } else {
497
+ loyalityStringsContent = await StringService.getStrings(
498
+ commonStringKeys
499
+ );
500
+ }
501
+ this.loyaltyStrings = loyalityStringsContent;
500
502
  // Link message to show to non-opted in users
501
503
  if (this.loyaltyStrings.productDisplayNotOptedinMessage) {
502
504
  this.loyaltyStatusAndLinks.landingPageLinkMessage = this.loyaltyStrings.productDisplayNotOptedinMessage;
@@ -538,12 +540,14 @@ const NsProductMixin = {
538
540
  );
539
541
  this.userLoyalty = loyaltyData;
540
542
  }
541
- });
542
543
 
543
- this.loyaltyStatusAndLinks.landingPage = this.localeReplace(
544
- this.loyaltyStatusAndLinks.dashboardPage
545
- );
546
- this.loyaltyStatusAndLinks.siteUrl = this.siteUrl;
544
+ this.loyaltyStatusAndLinks.landingPage = this.localeReplace(
545
+ this.loyaltyStatusAndLinks.dashboardPage
546
+ );
547
+ this.loyaltyStatusAndLinks.siteUrl = this.siteUrl;
548
+ } catch (err) {
549
+ console.warn("Unable to retrieve loyalty strings translations.", err);
550
+ }
547
551
  }
548
552
  },
549
553
 
@@ -672,25 +676,31 @@ const NsProductMixin = {
672
676
  if (this.product) {
673
677
  // WARNING: There's a instanceof check on CartService.getAddToCartQty for the ns-shop Product, previously different
674
678
  const shopProduct = new ShopProduct(this.product);
675
- // check if a user is qualified to purchase the product
676
- CartService.getAddToCartQty(shopProduct)
677
- .then(productQuantity => {
678
- // WARNING: this.product is volatile here. re-check is using this.product.
679
- this.maxQuantity = Math.min(
680
- shopProduct.maxQuantity,
681
- shopProduct.availableQuantity,
682
- productQuantity
683
- );
684
- })
685
- .catch(error => {
686
- this.maxQuantity = 0;
687
- console.error("Failed to retrieve add to cart quantity.", error);
688
- })
689
- .finally(() => {
690
- this.setStatus();
691
- this.checkedQualifications = true;
692
- this.emitAvailability();
693
- });
679
+
680
+ getConfiguration(["Equinox_Markets"]).then(({ Equinox_Markets }) => {
681
+ const { active } = Equinox_Markets;
682
+
683
+ const cartService = active ? EquinoxCartService : CartService;
684
+ // check if a user is qualified to purchase the product
685
+ cartService
686
+ .getAddToCartQty(shopProduct)
687
+ .then(productQuantity => {
688
+ // WARNING: this.product is volatile here. re-check is using this.product.
689
+ this.maxQuantity = Math.min(
690
+ shopProduct.maxQuantity,
691
+ productQuantity
692
+ );
693
+ })
694
+ .catch(error => {
695
+ this.maxQuantity = shopProduct.maxQuantity;
696
+ console.error("Failed to retrieve add to cart quantity.", error);
697
+ })
698
+ .finally(() => {
699
+ this.setStatus();
700
+ this.checkedQualifications = true;
701
+ this.emitAvailability();
702
+ });
703
+ });
694
704
  }
695
705
  },
696
706
 
@@ -723,6 +733,24 @@ const NsProductMixin = {
723
733
  )
724
734
  );
725
735
  this.statusMessageKey = "backOrderedWithDate";
736
+
737
+ let backOrderDate = new Date(this.product.backOrderDate);
738
+ let today = new Date();
739
+ if (backOrderDate < today) {
740
+ if (this.product.availableQuantity > 0) {
741
+ this.statusMessage = "";
742
+ this.statusMessageKey = "releasedForSale";
743
+ //BRW-4541 -- Only allow to purchase the atpQuantity if backorder date is in the past
744
+ this.maxQuantity = Math.min(
745
+ this.product.maxQuantity,
746
+ this.product.availableQuantity
747
+ );
748
+ } else {
749
+ this.statusMessage = this.localTranslations.outOfStock;
750
+ this.statusMessageKey = "outOfStock";
751
+ this.disable();
752
+ }
753
+ }
726
754
  }
727
755
  } else {
728
756
  this.disable();
@@ -755,9 +783,9 @@ const NsProductMixin = {
755
783
  this.exclusiveOfferMessage = "";
756
784
  if (this.isExclusive) {
757
785
  if (this.isLoggedIn) {
758
- const productQualification = await (
759
- await getQualificationService()
760
- ).getQualification(this.activeSku);
786
+ const productQualification = await QualificationService.getQualification(
787
+ this.activeSku
788
+ );
761
789
 
762
790
  let cartQuantity = 0;
763
791
 
@@ -787,10 +815,10 @@ const NsProductMixin = {
787
815
  cartQuantity = (cartItem || {}).qty || 0;
788
816
  } else {
789
817
  const cartData =
790
- (await (
791
- await getQualificationService()
792
- ).convertCartDataToBaseSkus(CartService.getItemData(), true)) ||
793
- {};
818
+ (await QualificationService.convertCartDataToBaseSkus(
819
+ CartService.getItemData(),
820
+ true
821
+ )) || {};
794
822
  const cartItem = cartData[this.baseSku] || {};
795
823
  cartQuantity = cartItem.qty || 0;
796
824
  }
@@ -835,22 +863,8 @@ const NsProductMixin = {
835
863
  * Set product pricing
836
864
  */
837
865
  setStandardPricing() {
838
- const equinoxMarketsConfig = getCachedConfiguration("Equinox_Markets");
839
- const isGraphQLActive = equinoxMarketsConfig.MySite_graphql_active;
840
-
841
866
  // set price and points
842
867
  this.originalPrice = this.product.getPricing(PriceType.WRTL);
843
-
844
- //graphQL adjustments
845
- if (isGraphQLActive) {
846
- this.originalPrice =
847
- this.product.childSkus &&
848
- this.product.childSkus.length &&
849
- this.getPriceType() === PriceType.WWHL
850
- ? this.product.getPricing(PriceType.WHL)
851
- : this.product.getPricing(PriceType.RTL);
852
- }
853
-
854
868
  this.priceType = this.getPriceType();
855
869
  this.price = this.product.getPricing(this.priceType);
856
870
  this.points = this.product.getPvFixed();
@@ -902,33 +916,20 @@ const NsProductMixin = {
902
916
  // set sales event pricing and points
903
917
  this.originalPriceType = this.product.priceType;
904
918
 
905
- this.originalPrice =
906
- isEquinoxEnabled && !isGraphQLActive
907
- ? this.product.getPricing(PriceType.WRTL)
908
- : this.product.getOriginalPrice();
909
-
910
- //workaround for graphQL active to show original price
911
919
  if (isGraphQLActive) {
912
- this.originalPrice =
913
- this.product.childSkus &&
914
- this.product.childSkus.length &&
915
- this.getPriceType() === PriceType.WWHL
916
- ? this.product.getPricing(PriceType.WHL)
917
- : this.product.getPricing(PriceType.RTL);
920
+ this.originalPrice = this.product.getPricing(this.originalPriceType);
921
+ this.product.priceType = `${this.eventName}-${this.originalPriceType}`;
922
+ } else {
923
+ this.product.getOriginalPrice();
918
924
  }
919
925
 
920
926
  this.priceType = this.product.priceType;
921
-
922
- this.price = this.product.getPrice();
927
+ this.price = this.product.getPricing(this.priceType);
923
928
 
924
929
  //If EQ market, always show the discounted price if product has promotion
925
930
  //Hence, we set the price to member(wholesale / PriceType.WADW) if the price type PriceType.WADR (retail)
926
931
  //this is inline with the change in business rules to always show the discounted prices
927
- if (
928
- isEquinoxEnabled &&
929
- !isGraphQLActive &&
930
- this.getAdrPriceType() == PriceType.WADR
931
- ) {
932
+ if (isGraphQLActive && this.getAdrPriceType() == PriceType.WADR) {
932
933
  this.adrPrice = this.product.getPricing(PriceType.WADW);
933
934
  }
934
935
 
@@ -937,13 +938,9 @@ const NsProductMixin = {
937
938
  //for product that has promotion
938
939
  //set the price to WWHL if this.getPriceType() === WRTL
939
940
  //promotion price is set in product.js setPriceAndPvFromType function
940
- if (
941
- isEquinoxEnabled &&
942
- !isGraphQLActive &&
943
- this.getPriceType() == PriceType.WRTL
944
- ) {
945
- this.price = this.product.getPricing(PriceType.WWHL);
946
- }
941
+ // if (isGraphQLActive && this.getPriceType() == PriceType.WRTL) {
942
+ // this.price = this.product.getPricing(PriceType.WWHL);
943
+ // }
947
944
 
948
945
  if (this.user && this.isDistributor) {
949
946
  this.points = this.product.getPvFixed();
@@ -1162,6 +1159,14 @@ const NsProductMixin = {
1162
1159
  productToAdd.equinoxProductId = productIdentifier;
1163
1160
  //productToAdd.properties = productData.products[0].properties
1164
1161
  }
1162
+ if (
1163
+ productToAdd.backOrderDate &&
1164
+ new Date(productToAdd.backOrderDate) > new Date()
1165
+ ) {
1166
+ productToAdd.inventory = "BACKORDER";
1167
+ productToAdd.properties.isBackOrdered = true;
1168
+ productToAdd.properties.inventoryStatus = "BACKORDER";
1169
+ }
1165
1170
  options.product = new ShopProduct(productToAdd);
1166
1171
  options.add = {
1167
1172
  item: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/product-components",
3
- "version": "3.18.0-cx24-6773.1",
3
+ "version": "3.18.0-td-341.2",
4
4
  "description": "Nu Skin Product Components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,8 +29,8 @@
29
29
  "@nuskin/ns-core-styles": "2.11.2",
30
30
  "@nuskin/ns-icon": "^2.12.0",
31
31
  "@nuskin/ns-loyalty-web": "1.5.6",
32
- "@nuskin/ns-product-lib": "2.16.0",
33
- "@nuskin/ns-shop": "6.11.7",
32
+ "@nuskin/ns-product-lib": "2.19.2",
33
+ "@nuskin/ns-shop": "7.1.3",
34
34
  "@nuskin/product-recommendation": "2.0.1",
35
35
  "axios": "1.6.7",
36
36
  "lodash": "4.17.21",
@@ -41,6 +41,8 @@ const buildPayload = product => {
41
41
  let personalOffer = sessionStorage.getItem("personalOffer");
42
42
  if (personalOffer !== null) {
43
43
  personalOffer = JSON.parse(personalOffer);
44
+ } else {
45
+ personalOffer = { products: [] };
44
46
  }
45
47
  const matchedProduct = personalOffer.products.filter(
46
48
  offerProduct => offerProduct.sku === product.sku
@@ -55,18 +57,45 @@ const buildPayload = product => {
55
57
  const skus = [];
56
58
  if (product && product.childSkus) {
57
59
  product.childSkus.forEach(childSku => {
58
- if (childSku.type === "MANDATORY") {
60
+ if (
61
+ childSku.type === "MANDATORY" &&
62
+ !skus.some(sku => sku.productId === childSku.productId)
63
+ ) {
59
64
  skus.push({
60
- skuId:
61
- selectedVariants !== null && selectedVariants[childSku.productId]
62
- ? selectedVariants[childSku.productId]
63
- : childSku.skuId,
65
+ skuId: childSku.skuId,
64
66
  productId: childSku.productId,
65
- quantity: childSku.skuQuantity,
66
- type: "bundle"
67
+ type: "bundle",
68
+ quantity: childSku.skuQuantity
67
69
  });
68
70
  }
69
71
  });
72
+
73
+ if (selectedVariants !== null) {
74
+ for (const productId in selectedVariants) {
75
+ let isOptionalProduct = true;
76
+ skus.forEach(finalSku => {
77
+ if (finalSku.productId === productId) {
78
+ isOptionalProduct = false;
79
+ finalSku.skuId = selectedVariants[productId];
80
+ }
81
+ });
82
+
83
+ if (isOptionalProduct) {
84
+ // this means this is optional product
85
+ const optionalProduct = product.childSkus.filter(
86
+ childSku => childSku.productId === productId
87
+ )[0];
88
+ if (optionalProduct) {
89
+ skus.push({
90
+ skuId: selectedVariants[productId],
91
+ productId: optionalProduct.productId,
92
+ type: "bundle",
93
+ quantity: optionalProduct.skuQuantity
94
+ });
95
+ }
96
+ }
97
+ }
98
+ }
70
99
  }
71
100
 
72
101
  payload.skus = skus;
@@ -3,8 +3,11 @@ import Vue from "vue";
3
3
  import {
4
4
  RunConfigService,
5
5
  ConfigService,
6
- StringService
6
+ StringService,
7
+ csStringService
7
8
  } from "@nuskin/ns-util";
9
+ import { getConfiguration } from "@nuskin/configuration-sdk";
10
+ import { isEnabled } from "@nuskin/ns-feature-flags";
8
11
 
9
12
  import { isNullOrEmpty } from "@nuskin/ns-common-lib";
10
13
 
@@ -34,7 +37,8 @@ if (!NsProductAppService) {
34
37
  showWholeSalePricing: false,
35
38
  loadingConfig: true,
36
39
  translations: {},
37
- loadingTranslations: true
40
+ loadingTranslations: true,
41
+ useCSResources: false
38
42
  };
39
43
  },
40
44
  computed: {
@@ -177,10 +181,37 @@ if (!NsProductAppService) {
177
181
  ];
178
182
 
179
183
  try {
180
- const commonStrings = await StringService.getStrings(
181
- commonStringKeys,
182
- this.locale
183
- );
184
+ const configs = await getConfiguration(["Mysite_Product_Offer"]);
185
+ let url = window.location.href;
186
+ let isStaticApp = url.match(/\/static\//) !== null;
187
+ let useCSResources = false;
188
+ if (
189
+ configs &&
190
+ configs.Mysite_Product_Offer &&
191
+ configs.Mysite_Product_Offer.useCSResources &&
192
+ Array.isArray(configs.Mysite_Product_Offer.useCSResources)
193
+ ) {
194
+ useCSResources = configs.Mysite_Product_Offer.useCSResources.includes(
195
+ this.runConfig.country
196
+ );
197
+ }
198
+ // For static apps by default use CS resources
199
+ // For AEM apps use CS resources only if the feature flag is enabled
200
+ this.useCSResources =
201
+ useCSResources &&
202
+ (isStaticApp || (!isStaticApp && isEnabled("td_341")));
203
+ let commonStrings = {};
204
+ if (this.useCSResources) {
205
+ commonStrings = await csStringService.getStrings(
206
+ commonStringKeys,
207
+ this.locale
208
+ );
209
+ } else {
210
+ commonStrings = await StringService.getStrings(
211
+ commonStringKeys,
212
+ this.locale
213
+ );
214
+ }
184
215
 
185
216
  this.appendTranslations(commonStrings);
186
217
  } catch (err) {
@@ -94,14 +94,14 @@ function getProductGraphqlUrl() {
94
94
 
95
95
  switch (env) {
96
96
  case "dev":
97
- return "https://test.nuskin.com/product-api/graphql";
97
+ return "https://product.api.dev.nuskin.com/graphql";
98
98
  case "stage":
99
99
  case "test":
100
- return "https://test.nuskin.com/product-api/graphql";
100
+ return "https://product.api.test.nuskin.com/graphql";
101
101
  case "unknown":
102
102
  case "prod":
103
103
  default:
104
- return "https://www.nuskin.com/product-api/graphql";
104
+ return "https://product.api.nuskin.com/graphql";
105
105
  }
106
106
  }
107
107
 
@@ -9,7 +9,10 @@ import { isNullOrEmpty } from "@nuskin/ns-common-lib";
9
9
  import { ProductDataService } from "@nuskin/ns-product";
10
10
  import { Product, PriceType } from "@nuskin/ns-product-lib";
11
11
  import { equinoxLocalStorage } from "@nuskin/ns-util";
12
- import { getConfiguration } from "@nuskin/configuration-sdk";
12
+ import {
13
+ getConfiguration,
14
+ getCachedConfiguration
15
+ } from "@nuskin/configuration-sdk";
13
16
 
14
17
  class ProductDataBatch {
15
18
  constructor(id, skus) {
@@ -269,9 +272,7 @@ if (!NsProductDataService) {
269
272
  return;
270
273
  }
271
274
 
272
- const equinoxMarketConfig = (
273
- await getConfiguration(["Equinox_Markets"])
274
- ).Equinox_Markets;
275
+ const equinoxMarketConfig = getCachedConfiguration("Equinox_Markets");
275
276
 
276
277
  // product data response has products
277
278
  if (productData.count && productData.products.length) {
@@ -200,40 +200,11 @@
200
200
  </template>
201
201
 
202
202
  <script>
203
- import {
204
- QualificationService as OldQualificationService,
205
- CartService
206
- } from "@nuskin/ns-shop";
207
- import { getConfiguration } from "@nuskin/configuration-sdk";
208
- import { default as NewQualificationService } from "@nuskin/exclusive-offer-sdk";
203
+ import { CartService } from "@nuskin/ns-shop";
204
+ import QualificationService from "@nuskin/exclusive-offer-sdk";
209
205
  import NsProductMixin from "../mixins/NsProductMixin";
210
206
  import "@nuskin/ns-core-styles/src/dist/main.css";
211
207
 
212
- let equinoxMarket = {
213
- promise: getConfiguration(["Equinox_Markets"]).then(config => {
214
- equinoxMarket = {
215
- value:
216
- config && config.Equinox_Markets
217
- ? !!config.Equinox_Markets.active
218
- : false,
219
- promise: null,
220
- loaded: true
221
- };
222
- }),
223
- loaded: false,
224
- value: undefined
225
- };
226
-
227
- const getQualificationService = async () => {
228
- if (!equinoxMarket.loaded) {
229
- await equinoxMarket.promise;
230
- }
231
- if (equinoxMarket.value) {
232
- return NewQualificationService;
233
- }
234
- return OldQualificationService;
235
- };
236
-
237
208
  export default {
238
209
  name: "NsProductMixinPreview",
239
210
  filters: {
@@ -407,9 +378,9 @@ export default {
407
378
  async mounted() {
408
379
  if (this.isExclusive) {
409
380
  if (this.isLoggedIn) {
410
- this.productQualification = await (
411
- await getQualificationService()
412
- ).getQualification(this.activeSku);
381
+ this.productQualification = await QualificationService.getQualification(
382
+ this.activeSku
383
+ );
413
384
 
414
385
  this.cartItem = await CartService.getFirstItemBySku(this.activeSku, {
415
386
  cartOrderItems: true