@ordergroove/offers 2.27.23 → 2.28.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.
@@ -0,0 +1,79 @@
1
+ // Karma configuration
2
+ // Generated on Mon Apr 01 2019 14:32:09 GMT-0400 (EDT)
3
+
4
+ module.exports = function(config) {
5
+ config.set({
6
+ // frameworks to use
7
+ // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
8
+ frameworks: ['jasmine'],
9
+
10
+ // list of files / patterns to load in the browser
11
+ files: [
12
+ {
13
+ pattern: 'src/init-shopify-tests.js',
14
+ type: 'js',
15
+ included: true,
16
+ served: true
17
+ },
18
+ {
19
+ pattern: 'src/shopify/**/*.spec.js',
20
+ type: 'js',
21
+ included: true,
22
+ served: true
23
+ }
24
+ ],
25
+
26
+ // list of files / patterns to exclude
27
+ exclude: [],
28
+
29
+ // preprocess matching files before serving them to the browser
30
+ // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
31
+ preprocessors: {
32
+ '**/*.js': ['esbuild']
33
+ },
34
+
35
+ esbuild: {
36
+ // Replace some global variables
37
+ define: {
38
+ // COVERAGE: coverage,
39
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || ''),
40
+ ENABLE_PERFORMANCE: true
41
+ },
42
+ // plugins: [createEsbuildPlugin()],
43
+
44
+ // Karma-esbuild specific options
45
+ singleBundle: false // Merge all test files into one bundle(default: true)
46
+ // singleBundle: true // Merge all test files into one bundle(default: true)
47
+ },
48
+
49
+ // test results reporter to use
50
+ // possible values: 'dots', 'progress'
51
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
52
+ reporters: ['spec'],
53
+
54
+ // web server port
55
+ port: 9876,
56
+
57
+ // enable / disable colors in the output (reporters and logs)
58
+ colors: true,
59
+
60
+ // level of logging
61
+ // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
62
+ logLevel: config.LOG_DEBUG,
63
+
64
+ // enable / disable watching file and executing tests whenever any file changes
65
+ autoWatch: true,
66
+
67
+ // start these browsers
68
+ // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
69
+ browsers: ['ChromeHeadless'],
70
+
71
+ // Continuous Integration mode
72
+ // if true, Karma captures browsers, runs the tests and exits
73
+ singleRun: false,
74
+
75
+ // Concurrency level
76
+ // how many browser should be started simultaneous
77
+ concurrency: Infinity
78
+ });
79
+ };
package/karma.conf.js CHANGED
@@ -17,7 +17,7 @@ module.exports = function(config) {
17
17
  served: true
18
18
  },
19
19
  {
20
- pattern: 'src/**/*.spec.js',
20
+ pattern: 'src/!(shopify)/**/*.spec.js',
21
21
  type: 'js',
22
22
  included: true,
23
23
  served: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/offers",
3
- "version": "2.27.23",
3
+ "version": "2.28.1",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -17,7 +17,9 @@
17
17
  "bundlesize": "../../node_modules/.bin/bundlesize",
18
18
  "lint": "../../node_modules/.bin/eslint --ignore-path ../../.gitignore ./src",
19
19
  "prepublishOnly": "npm run -s build:prod && npm run -s bundlesize",
20
- "test": "../../node_modules/.bin/karma start --single-run --log-level error --reporters progress && npm run build && ../../node_modules/.bin/karma start --single-run --log-level error --reporters progress karma-functional.conf.js",
20
+ "test": "../../node_modules/.bin/karma start --single-run --log-level error --reporters progress && npm run test:shopify && npm run build && ../../node_modules/.bin/karma start --single-run --log-level error --reporters progress karma-functional.conf.js",
21
+ "test:shopify": "../../node_modules/.bin/karma start karma-shopify.conf.js --single-run --log-level error --reporters progress",
22
+ "test:watch:shopify": "../../node_modules/.bin/karma start karma-shopify.conf.js",
21
23
  "test:watch": "../../node_modules/.bin/karma start",
22
24
  "test:watch:functional": "npm run build && ../../node_modules/.bin/karma start karma-functional.conf.js",
23
25
  "test:functional": "npm run test:watch:functional -- --single-run --log-level error --reporters progress",
@@ -34,7 +36,7 @@
34
36
  ],
35
37
  "dependencies": {
36
38
  "@ordergroove/auth": "^2.3.0",
37
- "@ordergroove/offers-live-editor": "^0.6.0",
39
+ "@ordergroove/offers-live-editor": "^0.6.1",
38
40
  "lit-element": "^2.1.0",
39
41
  "lodash.memoize": "^4.1.2",
40
42
  "logical-expression-parser": "1.0.0",
@@ -45,5 +47,5 @@
45
47
  "devDependencies": {
46
48
  "@ordergroove/offers-templates": "^0.4.16"
47
49
  },
48
- "gitHead": "474581ad550212f9ee3f15ab60c7aff06bb4e3b6"
50
+ "gitHead": "30db419a37eeddd12f09976a4eab2b5bb40cfbf8"
49
51
  }
@@ -312,6 +312,7 @@ export class Offer extends TemplateElement {
312
312
 
313
313
  get defaultFrequency() {
314
314
  const storeFrequency = this.productFrequency || this.productDefaultFrequency;
315
+
315
316
  if (storeFrequency) {
316
317
  return storeFrequency;
317
318
  }
@@ -4,6 +4,8 @@ import { OptinStatus, mapStateToProps } from './OptinStatus';
4
4
  import { connect } from '../core/connect';
5
5
  import { defaultFrequency } from '../core/props';
6
6
  import { resolveProduct } from '../core/resolveProperties';
7
+ import { frequencyToSellingPlan } from '../core/utils';
8
+ import platform from '../platform';
7
9
 
8
10
  export class OptinButton extends OptinStatus {
9
11
  static get properties() {
@@ -15,12 +17,30 @@ export class OptinButton extends OptinStatus {
15
17
  };
16
18
  }
17
19
 
20
+ updated(changed) {
21
+ if (changed.has('subscribed')) {
22
+ this.frequencyMatch = this.frequency === this.optinFrequency;
23
+ }
24
+ }
25
+
26
+ get optinFrequency() {
27
+ let freq;
28
+
29
+ // use the attribute since this.defaultFrequency comes from mapStateToProps and contains more logic
30
+ if (this.hasAttribute('default-frequency')) {
31
+ freq = this.getAttribute('default-frequency');
32
+ } else {
33
+ freq = this.offer ? this.offer.defaultFrequency : this.defaultFrequency;
34
+ }
35
+ if (platform.shopify_selling_plans && this.store) {
36
+ freq = frequencyToSellingPlan(freq, this.store.getState().config);
37
+ }
38
+
39
+ return freq;
40
+ }
41
+
18
42
  handleClick(ev) {
19
- this.optinProduct(
20
- resolveProduct(this),
21
- this.offer ? this.offer.defaultFrequency : this.defaultFrequency,
22
- this.offer
23
- );
43
+ this.optinProduct(resolveProduct(this), this.optinFrequency, this.offer);
24
44
  ev.preventDefault();
25
45
  }
26
46
 
@@ -35,10 +35,8 @@ export class OptinSelect extends withChildOptions(OptinStatus) {
35
35
  if (!this.subscribed) {
36
36
  return 'optedOut';
37
37
  }
38
- if (this.frequency) {
39
- return this.frequency;
40
- }
41
- return this.defaultFrequency;
38
+
39
+ return this.frequency || this.productDefaultFrequency || this.defaultFrequency;
42
40
  }
43
41
 
44
42
  onOptinChange(value) {
@@ -1,6 +1,7 @@
1
1
  import { html, css } from 'lit-element';
2
2
  import {
3
3
  makeOptedinSelector,
4
+ makeProductDefaultFrequencySelector,
4
5
  makeProductFrequencySelector,
5
6
  configSelector,
6
7
  templatesSelector
@@ -14,7 +15,9 @@ export class OptinStatus extends withProduct(TemplateElement) {
14
15
  static get properties() {
15
16
  return {
16
17
  subscribed,
17
- frequencyMatch: { type: Boolean, reflect: true, attribute: 'frequency-match' }
18
+ frequencyMatch: { type: Boolean, reflect: true, attribute: 'frequency-match' },
19
+ productDefaultFrequency: { type: String },
20
+ defaultFrequency: { type: String }
18
21
  };
19
22
  }
20
23
 
@@ -121,6 +124,7 @@ export class OptinStatus extends withProduct(TemplateElement) {
121
124
  export const mapStateToProps = (state, ownProps = {}) => ({
122
125
  subscribed: makeOptedinSelector(ownProps.product)(state),
123
126
  frequency: makeProductFrequencySelector(ownProps.product)(state),
127
+ productDefaultFrequency: makeProductDefaultFrequencySelector((ownProps.product || {}).id)(state),
124
128
  ...configSelector(state, ownProps, 'defaultFrequency'),
125
129
  ...templatesSelector(state, ownProps)
126
130
  });
@@ -49,8 +49,15 @@ export class OptinToggle extends OptinStatus {
49
49
  }
50
50
 
51
51
  handleClick(ev) {
52
- if (this.subscribed) this.optoutProduct(this.product, this.offer);
53
- else this.optinProduct(this.product, this.frequency || this.defaultFrequency, this.offer);
52
+ if (this.subscribed) {
53
+ this.optoutProduct(this.product, this.offer);
54
+ } else {
55
+ this.optinProduct(
56
+ this.product,
57
+ this.frequency || this.productDefaultFrequency || this.defaultFrequency,
58
+ this.offer
59
+ );
60
+ }
54
61
  ev.preventDefault();
55
62
  }
56
63
 
@@ -19,7 +19,7 @@ const waitUpdate = async offer => {
19
19
  await offer.updateComplete;
20
20
  await new Promise(r => setTimeout(r, 10));
21
21
  };
22
- const mockOfferResponse = (productId, inStock = true, autoship = true) => {
22
+ const mockOfferResponse = (productId, inStock = true, autoship = true, defaultFrequency) => {
23
23
  return Promise.resolve({
24
24
  json() {
25
25
  return Promise.resolve({
@@ -33,7 +33,12 @@ const mockOfferResponse = (productId, inStock = true, autoship = true) => {
33
33
  incentives_display: {},
34
34
  incentives: {
35
35
  [productId]: { initial: [], ongoing: [] }
36
- }
36
+ },
37
+ ...(defaultFrequency && {
38
+ default_frequencies: {
39
+ [productId]: defaultFrequency
40
+ }
41
+ })
37
42
  });
38
43
  }
39
44
  });
@@ -210,4 +215,81 @@ describe('Offer', function() {
210
215
  expect(htmlSelectElement.innerText).toEqual('Buy one time\n2 weeks (recomended)\n1 month');
211
216
  });
212
217
  });
218
+
219
+ describe('optin default frequency tests', function() {
220
+ let element;
221
+ beforeEach(async () => {
222
+ og.offers.clear();
223
+ });
224
+
225
+ it('it should opt in with default frequency', async () => {
226
+ fetch.and.returnValue(mockOfferResponse(productIdInStock));
227
+ document.body.innerHTML = `
228
+ <og-offer product="${productIdInStock}">
229
+ <og-optout-button></og-optout-button>
230
+ <og-optin-button></og-optin-button>
231
+ <og-select-frequency default-text=" (recomended)">
232
+ <option value="optedOut">Buy one time</option>
233
+ <option value="2_2" selected="selected">2 weeks</option>
234
+ <option value="1_3">1 month </option>
235
+ </og-select-frequency>
236
+ </og-offer>
237
+ `;
238
+ element = document.querySelector('og-offer');
239
+ await new Promise(r => setTimeout(r, 10));
240
+
241
+ expect(fetch).toHaveBeenCalledTimes(1);
242
+
243
+ expect(og.offers.store.getState().optedin).toEqual([]);
244
+
245
+ document.querySelector('og-optin-button').click();
246
+ await element.updateComplete;
247
+ expect(og.offers.store.getState().optedin).toEqual([{ id: productIdInStock, frequency: '2_2' }]);
248
+ });
249
+
250
+ it('it should opt in with PSDF', async () => {
251
+ fetch.and.returnValue(mockOfferResponse(productIdInStock, true, true, { every: '5', period: '1' }));
252
+
253
+ document.body.innerHTML = `
254
+ <og-offer product="${productIdInStock}">
255
+ <og-optout-button></og-optout-button>
256
+ <og-optin-button></og-optin-button>
257
+ <og-select-frequency default-text=" (recomended)">
258
+ <option value="optedOut">Buy one time</option>
259
+ <option value="2_2" selected="selected">2 weeks</option>
260
+ <option value="1_3">1 month </option>
261
+ <option value="5_1">5 days </option>
262
+ </og-select-frequency>
263
+ </og-offer>
264
+ `;
265
+ element = document.querySelector('og-offer');
266
+ await new Promise(r => setTimeout(r, 10));
267
+
268
+ expect(fetch).toHaveBeenCalledTimes(1);
269
+
270
+ expect(og.offers.store.getState().optedin).toEqual([]);
271
+
272
+ document.querySelector('og-optin-button').click();
273
+ await element.updateComplete;
274
+ expect(og.offers.store.getState().optedin).toEqual([{ id: productIdInStock, frequency: '5_1' }]);
275
+ });
276
+
277
+ it('buttons only template should use attr frequency as first option', async () => {
278
+ fetch.and.returnValue(mockOfferResponse(productIdInStock, true, true, { every: '5', period: '1' }));
279
+ document.body.innerHTML = `
280
+ <og-offer product="${productIdInStock}" default-frequency="6_1">
281
+ <og-optin-button default-frequency="6_1">Six days</og-optin-button>
282
+ <og-optin-button default-frequency="13_1">thirteen days</og-optin-button>
283
+ <og-optin-button default-frequency="3_2">Three weeks</og-optin-button>
284
+ </og-offer>
285
+ `;
286
+ element = document.querySelector('og-offer');
287
+ await new Promise(r => setTimeout(r, 10));
288
+ expect(fetch).toHaveBeenCalledTimes(1);
289
+ expect(og.offers.store.getState().optedin).toEqual([]);
290
+ document.querySelector('[default-frequency="13_1"]').click();
291
+ await element.updateComplete;
292
+ expect(og.offers.store.getState().optedin).toEqual([{ id: productIdInStock, frequency: '13_1' }]);
293
+ });
294
+ });
213
295
  });
@@ -0,0 +1,26 @@
1
+ import { frequencyToSellingPlan } from '../utils';
2
+
3
+ describe('frequencyToSellingPlan', () => {
4
+ it('should return a selling plan from config', () => {
5
+ expect(
6
+ frequencyToSellingPlan('1_2', {
7
+ frequenciesEveryPeriod: ['1_1', '1_2', '1_3'],
8
+ frequencies: [123, 456, 789]
9
+ })
10
+ ).toEqual(456);
11
+ });
12
+
13
+ it('should return same input if it does not looks like a frequency ', () => {
14
+ expect(frequencyToSellingPlan(123, {})).toEqual(123);
15
+ expect(frequencyToSellingPlan('345', {})).toEqual('345');
16
+ });
17
+
18
+ it('should return original frequency if no frequency match', () => {
19
+ expect(
20
+ frequencyToSellingPlan('1_2', {
21
+ frequenciesEveryPeriod: ['1_1', '1_3'],
22
+ frequencies: [123, 789]
23
+ })
24
+ ).toEqual('1_2');
25
+ });
26
+ });
@@ -1,6 +1,8 @@
1
1
  import { createSelector } from 'reselect';
2
2
  import memoize from 'lodash.memoize';
3
3
  import { stringifyFrequency } from './api';
4
+ import platform from '../platform';
5
+ import { mapFrequencyToSellingPlan, safeProductId } from '../core/utils';
4
6
 
5
7
  memoize.Cache = Map;
6
8
 
@@ -21,6 +23,12 @@ function arraysEqual(a, b) {
21
23
  return true;
22
24
  }
23
25
 
26
+ function resolveFrequency(sellingPlans, frequenciesEveryPeriod, frequency) {
27
+ const ogFrequency = stringifyFrequency(frequency);
28
+ if (!platform.shopify_selling_plans) return ogFrequency;
29
+ return mapFrequencyToSellingPlan(sellingPlans, frequenciesEveryPeriod, ogFrequency);
30
+ }
31
+
24
32
  export const isSameProduct = (a, b) => {
25
33
  if (a === b) return true;
26
34
  if (typeof a === 'object' && typeof b === 'object' && a && b) {
@@ -48,6 +56,10 @@ export const autoshipSelector = state => state.autoshipByDefault || {};
48
56
 
49
57
  export const defaultFrequenciesSelector = state => state.defaultFrequencies || {};
50
58
 
59
+ export const sellingPlansSelector = state => state?.config?.frequencies || [];
60
+
61
+ export const frequenciesEveryPeriodSelector = state => state?.config?.frequenciesEveryPeriod || [];
62
+
51
63
  /**
52
64
  * Creates a function with state arguments that return the true when
53
65
  * productId is in the optedin array or not in optedout or autoship by default
@@ -110,7 +122,12 @@ export const makeProductFrequencySelector = memoize(productId =>
110
122
  export const makeProductDefaultFrequencySelector = memoize(productId =>
111
123
  createSelector(
112
124
  defaultFrequenciesSelector,
113
- defaultFrequencies => (defaultFrequencies[productId] && stringifyFrequency(defaultFrequencies[productId])) || null
125
+ sellingPlansSelector,
126
+ frequenciesEveryPeriodSelector,
127
+ (defaultFrequencies, sellingPlans, frequenciesEveryPeriod) =>
128
+ (defaultFrequencies[safeProductId(productId)] &&
129
+ resolveFrequency(sellingPlans, frequenciesEveryPeriod, defaultFrequencies[safeProductId(productId)])) ||
130
+ null
114
131
  )
115
132
  );
116
133
 
package/src/core/store.js CHANGED
@@ -3,6 +3,7 @@ import thunk from 'redux-thunk';
3
3
 
4
4
  import { loadState } from './localStorage';
5
5
  import { dispatchMiddleware, localStorageMiddleware, offerEvents } from './middleware';
6
+ import { waitUntilOffersReady } from './waitUntilOffersReady';
6
7
 
7
8
  export function makeStore(reducer, ...extraMiddlewares) {
8
9
  if (window.og && window.og.store) return window.og.store;
@@ -14,11 +15,11 @@ export function makeStore(reducer, ...extraMiddlewares) {
14
15
  typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
15
16
  ? // eslint-disable-next-line no-underscore-dangle
16
17
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
17
- // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
18
+ name: 'Ordergroove Offers'
18
19
  })
19
20
  : compose;
20
21
 
21
- const middlewares = [thunk, dispatchMiddleware, offerEvents];
22
+ const middlewares = [waitUntilOffersReady, thunk, dispatchMiddleware, offerEvents];
22
23
 
23
24
  let initial = {};
24
25
 
package/src/core/utils.ts CHANGED
@@ -36,7 +36,7 @@ export function resolveEnvAndMerchant() {
36
36
  }
37
37
 
38
38
  export const safeProductId = product => {
39
- if (!product ) return '';
39
+ if (!product) return '';
40
40
  let productId = `${product.id || product}`;
41
41
  if (platform?.shopify_selling_plans) {
42
42
  // we can't avoid make offer request since we need to know the upsell group and autoship by default
@@ -49,20 +49,29 @@ export const safeProductId = product => {
49
49
  /**
50
50
  * Returns the OG frequency if platform is running on selling plans
51
51
  * @param initialFrequency
52
- * @param config
52
+ * @param config
53
53
  */
54
- export const safeOgFrequency = (initialFrequency, config) => {
54
+ export const safeOgFrequency = (initialFrequency, config) => {
55
55
  if (platform.shopify_selling_plans) {
56
56
  const ix = config.frequencies?.indexOf(initialFrequency);
57
57
  if (ix >= 0 && config.frequenciesEveryPeriod[ix]) {
58
58
  return config.frequenciesEveryPeriod[ix];
59
- } else {
60
- throw `OG Can't convert selling_plan_id ${initialFrequency} to OG frequency every period`;
61
59
  }
62
60
  }
63
61
  return initialFrequency;
64
62
  };
65
63
 
64
+ export const frequencyToSellingPlan = (ogFrequency, config) => {
65
+ // og frequency contains underscore
66
+ if (!`${ogFrequency}`.includes('_')) return ogFrequency;
67
+ const ix = config.frequenciesEveryPeriod?.indexOf(ogFrequency);
68
+ if (ix >= 0 && config.frequenciesEveryPeriod[ix]) {
69
+ return config.frequencies[ix];
70
+ }
71
+
72
+ return ogFrequency;
73
+ };
74
+
66
75
  /**
67
76
  * Attempts to auto initialize the offer library reading the merchantId and env from
68
77
  * integration script i.e. <script src="http://static.ordergroove...."/>.
@@ -70,9 +79,19 @@ export const safeProductId = product => {
70
79
  */
71
80
  export function autoInitializeOffers(offers) {
72
81
  if (offers.isReady()) return;
82
+
83
+ console.info('OG offers are auto initializing');
84
+
73
85
  const [merchantId, env] = resolveEnvAndMerchant();
74
86
  if (!env && !merchantId) return;
75
- offers.initialize(merchantId, env);
87
+ const script = document.createElement('script');
88
+ script.onload = () => console.info('OG pull initialization chunk for merchant', merchantId, env);
89
+ script.onerror = () => offers.initialize(merchantId, env);
90
+ script.src = `${window.location.protocol}//${
91
+ env === ENV_PROD ? STATIC_HOST : STAGING_STATIC_HOST
92
+ }/${merchantId}/main.js?initOnly=true`;
93
+
94
+ document.head.appendChild(script);
76
95
  }
77
96
 
78
97
  export const clearCookie = cookieId => {
@@ -84,3 +103,23 @@ export function getCookieValue(cookieId) {
84
103
  const cookie = document.cookie.match(`(^|;) ?${cookieId}=([^;]*)(;|$)`);
85
104
  return cookie ? cookie[2] : null;
86
105
  }
106
+ export const isOgFrequency = frequency => !!(frequency && frequency?.includes('_'));
107
+
108
+ export const getFirstSellingPlan = (frequencies = []) => frequencies?.[0] || null;
109
+
110
+ export const hasShopifySellingPlans = (sellingPlans = [], frequenciesEveryPeriod = []) =>
111
+ !!(platform?.shopify_selling_plans && sellingPlans.length && frequenciesEveryPeriod.length);
112
+
113
+ export const mapFrequencyToSellingPlan = (sellingPlans, frequenciesEveryPeriod, frequency) => {
114
+ if (sellingPlans.length !== frequenciesEveryPeriod.length) {
115
+ return null;
116
+ }
117
+
118
+ const index = frequenciesEveryPeriod.findIndex(it => it === frequency);
119
+
120
+ if (index >= 0) {
121
+ return sellingPlans[index];
122
+ }
123
+
124
+ return null;
125
+ };
@@ -0,0 +1,66 @@
1
+ import { createSessionId, fetchAuth } from './actions';
2
+ import {
3
+ CREATED_SESSION_ID,
4
+ SET_ENVIRONMENT_DEV,
5
+ SET_ENVIRONMENT_PROD,
6
+ SET_ENVIRONMENT_STAGING,
7
+ SET_MERCHANT_ID
8
+ } from './constants';
9
+ import { listenLocalStorageChanges } from './localStorage';
10
+
11
+ const waitFor = () => {
12
+ let resolve, reject;
13
+ return [
14
+ new Promise((yes, no) => {
15
+ resolve = yes;
16
+ reject = no;
17
+ }),
18
+ resolve,
19
+ reject
20
+ ];
21
+ };
22
+ /**
23
+ * Middleware that awaits offers being initialized and resumes the regular actions after.
24
+ * @param {*} store
25
+ * @returns
26
+ */
27
+ export function waitUntilOffersReady(store) {
28
+ const [waitForSetEnv, resolveEnv] = waitFor();
29
+ const [waitForMerchantId, resolveMerchantId] = waitFor();
30
+ const [waitForSessionId, resolveSessionId] = waitFor();
31
+
32
+ waitForMerchantId.then(merchantId => {
33
+ const { sessionId } = store.getState();
34
+ if (!sessionId || (merchantId && !sessionId.startsWith(merchantId))) {
35
+ store.dispatch(createSessionId(merchantId));
36
+ } else {
37
+ resolveSessionId(sessionId);
38
+ }
39
+ });
40
+
41
+ const waitForReady = Promise.all([waitForMerchantId, waitForSetEnv, waitForSessionId]);
42
+
43
+ waitForReady.then(() => {
44
+ window.addEventListener('storage', listenLocalStorageChanges(store));
45
+ if (!store.getState().auth?.ts) {
46
+ store.dispatch(fetchAuth());
47
+ }
48
+ });
49
+
50
+ return next => async action => {
51
+ if (
52
+ SET_ENVIRONMENT_DEV === action.type ||
53
+ SET_ENVIRONMENT_STAGING === action.type ||
54
+ SET_ENVIRONMENT_PROD === action.type
55
+ ) {
56
+ resolveEnv(action.payload);
57
+ } else if (SET_MERCHANT_ID === action.type) {
58
+ resolveMerchantId(action.payload);
59
+ } else if (CREATED_SESSION_ID === action.type) {
60
+ resolveSessionId(action.payload);
61
+ } else {
62
+ await waitForReady;
63
+ }
64
+ next(action);
65
+ };
66
+ }
package/src/index.js CHANGED
@@ -34,15 +34,19 @@ export const setTemplates = offers.setTemplates;
34
34
  export const setupCart = offers.setupCart;
35
35
  export const setupProduct = offers.setupProduct;
36
36
  export const setupProducts = offers.setupProducts;
37
+ export const autoInit = () => autoInitializeOffers(offers);
38
+
37
39
  export { platform };
38
40
  export default offers.initialize;
39
-
40
41
  /*
41
42
  * Attempts to auto initialize the offer library reading the merchantId and env from
42
43
  * integration script i.e. <script src="http://static.ordergroove...."/>.
43
44
  * Useful when local develop using http redirects
44
45
  */
45
- onReady(() => autoInitializeOffers(offers));
46
+ if (process.env.NODE_ENV === 'development') {
47
+ console.info('%c Ordergroove Offers DEV MODE ', 'background: #222; color: #bada55');
48
+ onReady(autoInit);
49
+ }
46
50
 
47
51
  if (platform?.shopify_selling_plans) {
48
52
  onReady(() => authorizeShopifyCustomer(offers));
@@ -0,0 +1,7 @@
1
+ import { STATIC_HOST } from './core/constants';
2
+
3
+ const mainJs = document.createElement('script');
4
+ mainJs.setAttribute('id', `mock-main-js`);
5
+ mainJs.setAttribute('src', `http://${STATIC_HOST}`);
6
+ mainJs.dataset.shopifySellingPlans = true;
7
+ document.head.appendChild(mainJs);
package/src/make-api.js CHANGED
@@ -156,7 +156,11 @@ export default function makeApi(store) {
156
156
  */
157
157
  initialize(merchantId, env, authUrl) {
158
158
  // settings resolves once, before anything.
159
- if (!isReady) offers.resolveSettings(merchantId, env, window.og_settings, store);
159
+ if (isReady) {
160
+ console.warn('og.offers has been initialized already. Skipping.');
161
+ } else {
162
+ offers.resolveSettings(merchantId, env, window.og_settings, store);
163
+ }
160
164
 
161
165
  const state = store.getState();
162
166
  // dont re-trigger actions if value is the same. allowing set new authurl only
@@ -165,20 +169,6 @@ export default function makeApi(store) {
165
169
  // allow set new authUrl
166
170
  if (authUrl) offers.setAuthUrl(authUrl);
167
171
 
168
- if (isReady) {
169
- console.warn('og.offers has been initialized already. Skipping.');
170
- } else {
171
- window.addEventListener('storage', listenLocalStorageChanges(store));
172
- store.dispatch(actions.requestSessionId());
173
- }
174
-
175
- if (arguments.length === 3) {
176
- // fetch auth is not there already
177
- if (!store.getState().auth?.ts) {
178
- store.dispatch(actions.fetchAuth());
179
- }
180
- }
181
-
182
172
  isReady = true;
183
173
 
184
174
  return this;