@nuskin/ns-product-lib 2.7.2-cx24-3684.1 → 2.8.0-cx12-7493.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,18 +1,13 @@
1
- ## [2.7.2-cx24-3684.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.7.1...v2.7.2-cx24-3684.1) (2023-04-16)
1
+ # [2.8.0-cx12-7493.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.7.1...v2.8.0-cx12-7493.1) (2023-05-02)
2
2
 
3
3
 
4
4
  ### Fix
5
5
 
6
- * added event pricing (#CX24-3684) ([49d1467](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/49d1467eecb69437adb16e9c85d07c52dca21d26)), closes [#CX24-3684](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3684)
7
- * added event pricing (#CX24-3684) ([fca7e9b](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/fca7e9b9f01d99682ddff162db40b4a727d018c1)), closes [#CX24-3684](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3684)
8
- * Rebased to master ([65b08a7](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/65b08a7d2ed14ae431ac2a9218ad138716c5ea1c))
9
- * set original price as wholesale price (#CX24-3684) ([047c01c](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/047c01c04a7ba6b9b1a2a30d997574460fda36ea)), closes [#CX24-3684](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3684)
10
- * set original price as wholesale price (#CX24-3684) ([e1d5650](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/e1d5650da1bee59b19977c9af5da58b6ff08485d)), closes [#CX24-3684](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3684)
6
+ * lint and error fixes (#CX12-7493) ([632e74e](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/632e74ebefca8279cf5dceeb608fc9427f352096)), closes [#CX12-7493](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX12-7493)
11
7
 
12
- ### Release
8
+ ### New
13
9
 
14
- * Automated changes by GitLab pipeline [skip ci] ([edf7159](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/edf7159c70c164b5511f8d9a19d49663dad75296))
15
- * Automated changes by GitLab pipeline [skip ci] ([0a2a6a0](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/0a2a6a00edb579cf167928e0e9dd2d82089124a3))
10
+ * Begin work on new nsProduct.js (#CX12-7493) ([e2a4ec2](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/e2a4ec29ee495869ee6463a7f9a6896d1aa0f95b)), closes [#CX12-7493](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX12-7493)
16
11
 
17
12
  ## [2.7.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.7.0...v2.7.1) (2023-04-15)
18
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/ns-product-lib",
3
- "version": "2.7.2-cx24-3684.1",
3
+ "version": "2.8.0-cx12-7493.1",
4
4
  "description": "This project contains shared Product models and code between the backend and frontend.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -8,17 +8,21 @@ const config = {
8
8
  dev: {
9
9
  ...baseConfig,
10
10
  accessToken: 'cs74599c107573ea7f6c7a1413',
11
- env: 'public-dev'
11
+ env: 'public-dev',
12
+ graphqlUrl: 'https://dev.nuskin.com/product-api/graphql'
12
13
  },
13
14
  prod: {
14
15
  ...baseConfig,
15
16
  accessToken: 'cs7029c5e32f0e99978efc683d',
16
- env: 'public-prod'
17
+ env: 'public-prod',
18
+ graphqlUrl: 'https://www.nuskin.com/product-api/graphql'
19
+
17
20
  },
18
21
  test: {
19
22
  ...baseConfig,
20
23
  accessToken: 'cs67e9fdd60eb15c301add40ea',
21
- env: 'public-test'
24
+ env: 'public-test',
25
+ graphqlUrl: 'https://product.api.test.nuskin.com/graphql'
22
26
  }
23
27
  };
24
28
 
@@ -26,7 +30,7 @@ const config = {
26
30
  * getCredentials returns contentstack config.
27
31
  *
28
32
  * @param {string} env
29
- * @return {{accessToken: string; apiKey: string; env: string; url: string;}}
33
+ * @return {{accessToken: string; apiKey: string; env: string; graphqlUrl: string; url: string; }}
30
34
  */
31
35
  function getCredentials(env) {
32
36
  if (config[env] === undefined) {
package/src/index.js CHANGED
@@ -15,16 +15,20 @@ const ProductStatusMapper = require("./productStatusMapper.js");
15
15
  const ProductUtils = require("./productUtils.js");
16
16
  const ProductData = require("./productData.js");
17
17
  const CustomerTypes = require('./models/customerTypes');
18
+ const NsProduct = require('./nsProduct.js')
19
+ const GraphQLQueries = require('./models/productGraphQLQueries')
18
20
 
19
21
  module.exports = {
20
22
  Agelocme,
21
23
  Contentstack,
24
+ CustomerTypes,
25
+ GraphQLQueries,
26
+ NsProduct,
22
27
  PriceType,
23
28
  Product,
24
29
  ProductContentMapper,
25
30
  ProductStatus,
26
31
  ProductStatusMapper,
27
32
  ProductUtils,
28
- ProductData,
29
- CustomerTypes
33
+ ProductData
30
34
  };
@@ -0,0 +1,396 @@
1
+ 'use strict'
2
+
3
+ const VariantQuery = `
4
+ id
5
+ globalId
6
+ sku
7
+ slug
8
+ variantLabel
9
+ variantColor
10
+ title
11
+ salesLabel
12
+ salesText
13
+ description
14
+ nettoWeight
15
+ size
16
+ isExclusive
17
+ availableQuantity
18
+ maxQuantity
19
+ purchaseTypes {
20
+ buyOnce
21
+ subscription
22
+ }
23
+ matchingVariant
24
+ shadeable
25
+ productType
26
+ primaryBrand
27
+ brandFamily
28
+ marketAttributes {
29
+ discount
30
+ redeem
31
+ earn
32
+ }
33
+ disclaimers
34
+ restrictedMarkets
35
+ searchKeywords
36
+ excludeFromSearch
37
+ availableChannels
38
+ customerTypes
39
+ scanQualifiedCount
40
+ chargeShipping
41
+ dangerousGoods
42
+ channels
43
+ foreignOrderLimit
44
+ orderType
45
+ salesDisclaimer
46
+ productImages {
47
+ url
48
+ alt
49
+ thumbnail
50
+ }
51
+ productDetails {
52
+ description
53
+ includedItems
54
+ highlights {
55
+ iconUrl
56
+ label
57
+ }
58
+ originCountry
59
+ importer
60
+ warnings
61
+ }
62
+ ingredients {
63
+ keyIngredients {
64
+ name
65
+ description
66
+ image {
67
+ url
68
+ alt
69
+ thumbnail
70
+ }
71
+ }
72
+ nutritionInformationImage {
73
+ url
74
+ alt
75
+ thumbnail
76
+ }
77
+ productName
78
+ allIngredients
79
+ otherIngredients
80
+ activeIngredients
81
+ inactiveIngredients
82
+ ingredientDisclaimers
83
+ markdown
84
+ }
85
+ disclaimerWarnings {
86
+ icon {
87
+ url
88
+ alt
89
+ thumbnail
90
+ }
91
+ markdown
92
+ }
93
+ features {
94
+ image {
95
+ url
96
+ alt
97
+ thumbnail
98
+ }
99
+ subtitle
100
+ features
101
+ backgroundColor
102
+ textColor
103
+ }
104
+ benefits {
105
+ benefits
106
+ youTubeVideoId
107
+ image {
108
+ url
109
+ alt
110
+ thumbnail
111
+ }
112
+ }
113
+ results {
114
+ summary
115
+ results {
116
+ percentage
117
+ text
118
+ }
119
+ report {
120
+ url
121
+ text
122
+ }
123
+ youTubeVideoId
124
+ image {
125
+ url
126
+ alt
127
+ thumbnail
128
+ }
129
+ }
130
+ usage {
131
+ steps
132
+ recommendations
133
+ warnings
134
+ additionalText
135
+ youTubeVideoId
136
+ image {
137
+ url
138
+ alt
139
+ thumbnail
140
+ }
141
+ markdown
142
+ }
143
+ resources {
144
+ title
145
+ url
146
+ image {
147
+ url
148
+ alt
149
+ thumbnail
150
+ }
151
+ }
152
+ faqs {
153
+ question
154
+ answers
155
+ }
156
+ status {
157
+ status
158
+ isBackordered
159
+ backorderedAvailableDate
160
+ }
161
+ `;
162
+
163
+ const BundleProduct = `
164
+ type
165
+ price {
166
+ currencyCode
167
+ retail
168
+ wholesale
169
+ retailSales
170
+ wholesaleSales
171
+ retailSubscription
172
+ wholesaleSubscription
173
+ }
174
+ retailDiscount
175
+ wholesaleDiscount
176
+ pvDiscount
177
+ cvDiscount
178
+ sbDiscount
179
+ grpDiscount
180
+ availableChannels
181
+ customerTypes
182
+ purchaseTypes {
183
+ buyOnce
184
+ subscription
185
+ }
186
+ status {
187
+ status
188
+ isBackordered
189
+ backorderedAvailableDate
190
+ }
191
+ availableQuantity
192
+ chargeShipping
193
+ dangerousGoods
194
+ excludeFromSearch
195
+ isExclusive
196
+ marketAttributes {
197
+ discount
198
+ redeem
199
+ earn
200
+ }
201
+ restrictedMarkets
202
+ scanQualifiedCount
203
+ kitProducts {
204
+ quantity
205
+ isMandatory
206
+ product {
207
+ id
208
+ }
209
+ }
210
+ `;
211
+
212
+ const ProductQuery = `
213
+ id
214
+ slug
215
+ variantSelectLabel
216
+ title
217
+ productImages {
218
+ url
219
+ alt
220
+ thumbnail
221
+ }
222
+ salesLabel
223
+ salesText
224
+ description
225
+ salesDisclaimer
226
+ features {
227
+ image {
228
+ url
229
+ alt
230
+ thumbnail
231
+ }
232
+ subtitle
233
+ features
234
+ backgroundColor
235
+ textColor
236
+ }
237
+ productDetails {
238
+ description
239
+ includedItems
240
+ highlights {
241
+ iconUrl
242
+ label
243
+ }
244
+ originCountry
245
+ importer
246
+ warnings
247
+ }
248
+ benefits {
249
+ benefits
250
+ youTubeVideoId
251
+ image {
252
+ url
253
+ alt
254
+ thumbnail
255
+ }
256
+ }
257
+ results {
258
+ summary
259
+ results {
260
+ percentage
261
+ text
262
+ }
263
+ report {
264
+ url
265
+ text
266
+ }
267
+ youTubeVideoId
268
+ image {
269
+ url
270
+ alt
271
+ thumbnail
272
+ }
273
+ }
274
+ sustainability {
275
+ youTubeVideoId
276
+ description
277
+ highlights {
278
+ description
279
+ image {
280
+ url
281
+ alt
282
+ thumbnail
283
+ }
284
+ }
285
+ image {
286
+ url
287
+ alt
288
+ thumbnail
289
+ }
290
+ }
291
+ usage {
292
+ steps
293
+ recommendations
294
+ warnings
295
+ additionalText
296
+ youTubeVideoId
297
+ image {
298
+ url
299
+ alt
300
+ thumbnail
301
+ }
302
+ markdown
303
+ }
304
+ resources {
305
+ title
306
+ url
307
+ image {
308
+ url
309
+ alt
310
+ thumbnail
311
+ }
312
+ }
313
+ faqs {
314
+ question
315
+ answers
316
+ }
317
+ ingredients {
318
+ keyIngredients {
319
+ name
320
+ description
321
+ image {
322
+ url
323
+ alt
324
+ thumbnail
325
+ }
326
+ }
327
+ nutritionInformationImage {
328
+ url
329
+ alt
330
+ thumbnail
331
+ }
332
+ productName
333
+ allIngredients
334
+ otherIngredients
335
+ activeIngredients
336
+ inactiveIngredients
337
+ ingredientDisclaimers
338
+ markdown
339
+ }
340
+ disclaimers
341
+ disclaimerWarnings {
342
+ icon {
343
+ url
344
+ alt
345
+ thumbnail
346
+ }
347
+ markdown
348
+ }
349
+ seoInformation {
350
+ metaDescription
351
+ metaTitle
352
+ canonicalURL
353
+ ogImage {
354
+ url
355
+ alt
356
+ thumbnail
357
+ }
358
+ }
359
+ refundPolicy
360
+ shippingText
361
+ thirdPartyScripts
362
+ categories {
363
+ displayName
364
+ id
365
+ subcategories {
366
+ displayName
367
+ id
368
+ }
369
+ }
370
+ warranty
371
+ secondaryTitle
372
+ variants {
373
+ ${VariantQuery}
374
+ }
375
+ bundle {
376
+ ${BundleProduct}
377
+ }
378
+ productDataSource {
379
+ source
380
+ webBaseUrl
381
+ apiBaseUrl
382
+ storeId
383
+ }
384
+ error {
385
+ name
386
+ errors
387
+ lines
388
+ message
389
+ status
390
+ }
391
+ `;
392
+
393
+ module.exports = {
394
+ VariantQuery,
395
+ ProductQuery
396
+ }
@@ -0,0 +1,108 @@
1
+ 'use strict'
2
+
3
+ const axios = require('axios')
4
+ const {ProductQuery} = require('./models/productGraphQLQueries')
5
+ const config = require('./contentstack/environment')
6
+
7
+ let envConfig = {}
8
+
9
+ const processProps = (props) => {
10
+ if (!props) {
11
+ return "empty"
12
+ } else if (props.fromId) {
13
+ if(!props.env || !['dev', 'test', 'prod'].includes(props.env)) {
14
+ return "missingEnv"
15
+ }
16
+ else {
17
+ return "id"
18
+ }
19
+ } else if (props.fromSlug) {
20
+ if(!props.env || !['dev', 'test', 'prod'].includes(props.env)) {
21
+ return "missingEnv"
22
+ } else {
23
+ return "slug"
24
+ }
25
+ } else if (props.data) {
26
+ return "data"
27
+ }
28
+ }
29
+
30
+ const getProductById = async(id, market, language) => {
31
+ const payload = {variables:{market, language, id}}
32
+ payload.operationName = 'ProductById'
33
+ payload.query = `query ProductById($id: String!, $market: String, $language: String) {
34
+ productById(id: $id, market: $market, language: $language) {
35
+ ${ProductQuery}}}`
36
+ try {
37
+ const idRes = await axios.post(`${envConfig.graphqlUrl}`, payload);
38
+ return ((idRes.data || {}).data || {}).productById || idRes.error;
39
+ } catch(ex) {
40
+ console.error(ex)
41
+ }
42
+ }
43
+
44
+ const getProductBySlug = async(slug, market, language) => {
45
+ const payload = {variables:{market, language, slug}}
46
+ payload.operationName = 'ProductBySlug'
47
+ payload.query = `query ProductBySlug($slug: String!, $market: String, $language: String) {
48
+ productBySlug(slug: $slug, market: $market, language: $language) {
49
+ ${ProductQuery}}}`
50
+ try {
51
+ const idRes = await axios.post(`${envConfig.graphqlUrl}`, payload);
52
+ return ((idRes.data || {}).data || {}).productBySlug || idRes.error;
53
+ } catch(ex) {
54
+ console.error(ex)
55
+ }
56
+ }
57
+
58
+ /*
59
+ This is the "constructor" for a nuskin product object.
60
+ You send it an object that will be used to determine what to do when it initializes
61
+ Possible options:
62
+ {} - Create an empty nsProduct object with no data
63
+ {data: Object} - Create an object using the data previously retrived from the product graphql
64
+ {fromId: String, market: String, language: String, env: String} - Create an object using data retrieved using the ID, market, language, environment sent
65
+ {fromSlug: String, market: String, language: String, env: String} - Create an object using data retrieved using the slug, market, language, environment sent
66
+
67
+ Example usage:
68
+ const product = await nsProduct({fromSlug: 'tegreen', market: 'US', language: 'en', env: 'dev'});
69
+ const fromSku = await nsProduct({fromId: '01003440', market: 'US', language: 'en', env: 'dev'});
70
+ const fromUid = await nsProduct({fromId: 'blta50746fc33f83470', market: 'US', language: 'en', env: 'dev'});
71
+ */
72
+ const nsProduct = async (props) =>
73
+ {
74
+ let data = {}
75
+ // Validate props passed in
76
+ const constructorType = processProps(props)
77
+ if (constructorType === 'missingEnv') {
78
+ data.error = "Missing env in props, please include the environment and re-initialize"
79
+ } else if (['id', 'slug'].includes(constructorType)) {
80
+ // initialize configs and libs
81
+ envConfig = config.getCredentials(props.env);
82
+ }
83
+ // Initialize NsProduct based on constructor used
84
+ switch (constructorType) {
85
+ case "id":
86
+ data = await getProductById(props.fromId, props.market || 'US', props.language || 'en') || {}
87
+ break
88
+ case "slug":
89
+ data = await getProductBySlug(props.fromSlug, props.market || 'US', props.language || 'en') || {}
90
+ break
91
+ case "data":
92
+ data = props.data
93
+ break
94
+ }
95
+
96
+ const getPricing = async() => {
97
+ data.pricing = await "hello"
98
+ }
99
+
100
+ return {
101
+ data,
102
+ getPricing
103
+ }
104
+ }
105
+
106
+ module.exports = {
107
+ nsProduct
108
+ }
package/src/product.js CHANGED
@@ -75,7 +75,7 @@ const Product = function (productData) {
75
75
  //equinox inventory / stock label
76
76
  //@example "IN STOCK"
77
77
  this.inventory = "";
78
-
78
+
79
79
  // equinox specific properties
80
80
  this.equinoxProductId = "";
81
81
  this.properties = {};
@@ -262,7 +262,6 @@ const Product = function (productData) {
262
262
 
263
263
  if (option.isEqPromotion) {
264
264
  //retain product.price as original price
265
- this.setPrice(this.getPricing(priceType));
266
265
  this.setCv(this.getCvWithType(priceType));
267
266
  this.setPv(this.getPvWithType(priceType));
268
267
  this.priceType = priceType;
@@ -48,11 +48,11 @@ const ProductData = {
48
48
  },
49
49
 
50
50
  /**
51
- *
52
- * @param {string[]} skus
53
- * @param {string} locale
54
- * @param {ConfigMap} config
55
- * @returns
51
+ *
52
+ * @param {string[]} skus
53
+ * @param {string} locale
54
+ * @param {ConfigMap} config
55
+ * @returns
56
56
  */
57
57
  searchEquinoxProduct: async function (skus, locale, config) {
58
58
  let skuFilter = [];
@@ -140,7 +140,6 @@ const ProductData = {
140
140
  const discountedPrice = eventName ? computedPrice : eqVariant.priceFacets["Regular Price"];
141
141
  const productCVPrice = eventName ? CVPrice : eqVariant.priceFacets.CV;
142
142
  const productPVPrice = eventName ? PVPrice : eqVariant.priceFacets.PV;
143
- const wholeSalePrice = eventName ? defaultProductPrice : eqVariant.priceFacets["Wholesale Price"];
144
143
 
145
144
  return {
146
145
  "sku": eqVariant.identifier,
@@ -253,12 +252,12 @@ const ProductData = {
253
252
  "price": discountedPrice,
254
253
  "priceMap": {
255
254
  "WRTL": productPrice,
256
- "WADW-WRTL": productPrice,
257
- "WADR": productPrice,
258
- "RTL": productPrice,
259
- "WWHL": wholeSalePrice,
260
- "WADW": wholeSalePrice,
261
- "WHL": wholeSalePrice
255
+ "WADW-WRTL": eqVariant.priceFacets["Regular Price"],
256
+ "WADR": eqVariant.priceFacets["Regular Price"],
257
+ "RTL": eqVariant.priceFacets["Regular Price"],
258
+ "WWHL": eqVariant.priceFacets["Wholesale Price"],
259
+ "WADW": eqVariant.priceFacets["Wholesale Price"],
260
+ "WHL": eqVariant.priceFacets["Wholesale Price"]
262
261
  },
263
262
  "cvMap": {
264
263
  "WWHL": productCVPrice,
@@ -388,11 +387,9 @@ const ProductData = {
388
387
  PVPrice
389
388
  } = this.getEqProductPromotions(product);
390
389
  const productPrice = eventName ? defaultProductPrice : product.priceFacets["Regular Price"];
391
- const discountedPrice = eventName ? computedPrice : product.priceFacets["Wholesale Price"];
390
+ const discountedPrice = eventName ? computedPrice : product.priceFacets["Regular Price"];
392
391
  const productCVPrice = eventName ? CVPrice : product.priceFacets.CV;
393
392
  const productPVPrice = eventName ? PVPrice : product.priceFacets.PV;
394
- const wholeSalePrice = eventName ? defaultProductPrice : product.priceFacets["Wholesale Price"];
395
-
396
393
 
397
394
  product.childSkus = await this.fetchChildSkus(product);
398
395
  product.availableQuantity = mapAvailableQuantity(product);
@@ -436,13 +433,13 @@ const ProductData = {
436
433
  "priceType": "WRTL",
437
434
  "price": discountedPrice,
438
435
  "priceMap": {
439
- "WRTL": productPrice, //regular | retail price
440
- "WADW-WRTL": productPrice,
441
- "WADR": productPrice,
442
- "RTL": productPrice,
443
- "WADW": wholeSalePrice,
444
- "WHL": wholeSalePrice,
445
- "WWHL": wholeSalePrice
436
+ "WRTL": productPrice,
437
+ "WADW-WRTL": product.priceFacets["Regular Price"],
438
+ "WADR": product.priceFacets["Regular Price"],
439
+ "RTL": product.priceFacets["Regular Price"],
440
+ "WADW": product.priceFacets["Wholesale Price"],
441
+ "WHL": product.priceFacets["Wholesale Price"],
442
+ "WWHL": product.priceFacets["Wholesale Price"]
446
443
  },
447
444
  "cvMap": {
448
445
  "WWHL": productCVPrice,