@ordergroove/offers 2.26.11 → 2.27.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +34 -0
  3. package/build.js +3 -1
  4. package/dist/bundle-report.html +185 -116
  5. package/dist/offers.js +65 -76
  6. package/dist/offers.js.map +3 -3
  7. package/examples/cart.js +105 -0
  8. package/examples/index.html +2 -2
  9. package/examples/products/cheap-watch.js +183 -0
  10. package/examples/shopify-cart.html +26 -0
  11. package/examples/shopify-pdp.html +34 -0
  12. package/karma.conf.js +2 -1
  13. package/package.json +4 -4
  14. package/src/__tests__/offers.spec.js +35 -10
  15. package/src/components/FrequencyStatus.js +14 -11
  16. package/src/components/IncentiveText.js +2 -1
  17. package/src/components/Offer.js +14 -7
  18. package/src/components/OptinButton.js +1 -1
  19. package/src/components/OptinSelect.js +2 -2
  20. package/src/components/OptinToggle.js +2 -2
  21. package/src/components/OptoutButton.js +1 -1
  22. package/src/components/Price.js +7 -3
  23. package/src/components/Select.js +3 -13
  24. package/src/components/SelectFrequency.js +24 -6
  25. package/src/components/TestWizard.js +1 -1
  26. package/src/components/__tests__/OG.fspec.js +24 -0
  27. package/src/components/__tests__/Offer.spec.js +4 -4
  28. package/src/components/__tests__/OptinButton.spec.js +2 -2
  29. package/src/components/__tests__/OptinToggle.spec.js +2 -2
  30. package/src/components/__tests__/OptoutButton.spec.js +1 -1
  31. package/src/components/__tests__/SelectFrequency.fspec.js +1 -0
  32. package/src/components/__tests__/SelectFrequency.spec.js +1 -1
  33. package/src/components/__tests__/TestWizard.spec.js +2 -2
  34. package/src/components/__tests__/Text.spec.js +5 -1
  35. package/src/core/__tests__/actions.spec.js +6 -6
  36. package/src/core/actions.js +22 -17
  37. package/src/core/constants.js +21 -0
  38. package/src/core/descriptors.js +2 -1
  39. package/src/core/middleware.js +41 -1
  40. package/src/core/reducer.js +22 -21
  41. package/src/core/resolveProperties.js +2 -7
  42. package/src/core/selectors.js +1 -1
  43. package/src/core/store.js +17 -9
  44. package/src/core/utils.ts +67 -0
  45. package/src/index.js +46 -203
  46. package/src/make-api.js +195 -0
  47. package/src/platform.ts +9 -0
  48. package/src/shopify/__tests__/shopifyMiddleware.spec.js +126 -0
  49. package/src/shopify/__tests__/shopifyReducer.spec.js +489 -0
  50. package/src/shopify/shopifyBootstrap.ts +136 -0
  51. package/src/shopify/shopifyMiddleware.ts +336 -0
  52. package/src/shopify/shopifyReducer.js +254 -0
  53. package/tsconfig.json +35 -0
  54. package/examples/5starnutrition-main.js +0 -3
  55. package/examples/single-offer.html +0 -9
  56. package/src/init-test.js +0 -3
@@ -93,22 +93,17 @@ export const withProduct = Base =>
93
93
  export const withChildOptions = Base =>
94
94
  class extends Base {
95
95
  get childOptions() {
96
- return this._childOptions || { options: [] };
97
- }
98
-
99
- connectedCallback() {
100
96
  const options = [];
101
97
  let isSelected = null;
98
+
102
99
  this.querySelectorAll('option').forEach(it => {
103
100
  const value = sanitizeFrequencyString(it.value);
104
101
  const text = it.innerText.trim();
105
102
  options.push({ value, text });
106
-
107
103
  if (!isSelected && it.selected) {
108
104
  isSelected = value;
109
105
  }
110
106
  });
111
- this._childOptions = { options, isSelected };
112
- super.connectedCallback && super.connectedCallback();
107
+ return { options, isSelected };
113
108
  }
114
109
  };
@@ -133,9 +133,9 @@ export const kebabCase = string => {
133
133
  */
134
134
  export const configSelector = (state, element, key, defaultValue) => ({
135
135
  [key]:
136
+ (state.config && state.config[key]) ||
136
137
  (element && element.hasAttribute && element.hasAttribute(kebabCase(key)) && element[key]) ||
137
138
  (element.offer && typeof (element.offer[key] !== 'undefined') && element.offer[key]) ||
138
- (state.config && state.config[key]) ||
139
139
  defaultValue
140
140
  });
141
141
 
package/src/core/store.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { createStore, compose, applyMiddleware } from 'redux';
2
2
  import thunk from 'redux-thunk';
3
- import reducer from './reducer';
4
- import { loadState, saveState } from './localStorage';
5
- import { dispatchMiddleware, localStorageMiddleware } from './middleware';
6
3
 
7
- export function getStore() {
4
+ import { loadState } from './localStorage';
5
+ import { dispatchMiddleware, localStorageMiddleware, offerEvents } from './middleware';
6
+
7
+ export function makeStore(reducer, ...extraMiddlewares) {
8
8
  if (window.og && window.og.store) return window.og.store;
9
9
 
10
10
  const isPreviewMode = window.og && window.og.previewMode;
@@ -18,17 +18,25 @@ export function getStore() {
18
18
  })
19
19
  : compose;
20
20
 
21
- const middlewares = [thunk, dispatchMiddleware];
21
+ const middlewares = [thunk, dispatchMiddleware, offerEvents];
22
+
23
+ let initial = {};
24
+
22
25
  if (!isPreviewMode) {
23
- middlewares.push(localStorageMiddleware);
26
+ try {
27
+ initial = loadState();
28
+ middlewares.push(localStorageMiddleware);
29
+ } catch (err) {
30
+ // localStorage not available during preview in sandbox
31
+ }
24
32
  }
25
33
 
26
- const enhancer = composeEnhancers(applyMiddleware(...middlewares));
27
- const store = createStore(reducer, isPreviewMode ? {} : loadState(), enhancer);
34
+ const enhancer = composeEnhancers(applyMiddleware(...middlewares, ...extraMiddlewares));
35
+ const store = createStore(reducer, initial, enhancer);
28
36
 
29
37
  window.og = window.og || {};
30
38
  window.og.store = store;
31
39
  return store;
32
40
  }
33
41
 
34
- export default getStore;
42
+ export default makeStore;
@@ -0,0 +1,67 @@
1
+ import platform from '../platform';
2
+ import { ENV_PROD, ENV_STAGING, STAGING_STATIC_HOST, STATIC_HOST } from './constants';
3
+
4
+ export function onReady(fn) {
5
+ if (document.readyState === 'loading') {
6
+ window.addEventListener('DOMContentLoaded', fn);
7
+ } else {
8
+ fn();
9
+ }
10
+ }
11
+
12
+ export function getMainJs(): HTMLScriptElement {
13
+ return document.querySelector(
14
+ [
15
+ `script[src^="https://${STATIC_HOST}"]`,
16
+ `script[src^="https://${STAGING_STATIC_HOST}"]`,
17
+ `script[src^="http://${STATIC_HOST}"]`,
18
+ `script[src^="http://${STAGING_STATIC_HOST}"]`
19
+ ].join(',')
20
+ ) as HTMLScriptElement;
21
+ }
22
+ /**
23
+ *
24
+ * @returns array of two elements [merchantId, env];
25
+ */
26
+ export function resolveEnvAndMerchant() {
27
+ const script = getMainJs();
28
+ if (!script) return [];
29
+ const url = new URL(script.src);
30
+ const env = url.host.startsWith(ENV_STAGING) ? ENV_STAGING : ENV_PROD;
31
+ const merchantId = url.pathname.split('/')[1];
32
+
33
+ if (!env && !merchantId) return [];
34
+
35
+ return [merchantId, env, script];
36
+ }
37
+
38
+ export const safeProductId = product => {
39
+ let productId = `${product.id || product}`;
40
+ if (platform?.shopify_selling_plans) {
41
+ // we can't avoid make offer request since we need to know the upsell group and autoship by default
42
+ // cart offer contains <product>:<cart_id>, we care about product only
43
+ productId = productId.split(':')[0];
44
+ }
45
+ return productId;
46
+ };
47
+ /**
48
+ * Attempts to auto initialize the offer library reading the merchantId and env from
49
+ * integration script i.e. <script src="http://static.ordergroove...."/>.
50
+ * Useful when local develop using http redirects
51
+ */
52
+ export function autoInitializeOffers(offers) {
53
+ if (offers.isReady()) return;
54
+ const [merchantId, env] = resolveEnvAndMerchant();
55
+ if (!env && !merchantId) return;
56
+ offers.initialize(merchantId, env);
57
+ }
58
+
59
+ export const clearCookie = cookieId => {
60
+ // clear existing OG auth cookie
61
+ document.cookie = `${cookieId}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
62
+ };
63
+
64
+ export function getCookieValue(cookieId) {
65
+ const cookie = document.cookie.match(`(^|;) ?${cookieId}=([^;]*)(;|$)`);
66
+ return cookie ? cookie[2] : null;
67
+ }
package/src/index.js CHANGED
@@ -1,206 +1,49 @@
1
- import { offersLiveEditor } from '@ordergroove/offers-live-editor';
2
- import { setStore } from './core/connect';
3
- import { getStore } from './core/store';
4
- import { listenLocalStorageChanges } from './core/localStorage';
5
- import * as adapters from './core/adapters';
6
- import * as actions from './core/actions';
7
- import { ConnectedWhen } from './components/When';
8
- import { ConnectedOptinButton } from './components/OptinButton';
9
- import { ConnectedOptoutButton } from './components/OptoutButton';
10
- import { ConnectedOptinSelect } from './components/OptinSelect';
11
- import { ConnectedUpsellButton } from './components/UpsellButton';
12
- import { ConnectedUpsellModal } from './components/UpsellModal';
13
- import { ConnectedOptinToggle } from './components/OptinToggle';
14
- import { ConnectedOptinStatus } from './components/OptinStatus';
15
- import { ConnectedText } from './components/Text';
16
- import { ConnectedIncentiveText } from './components/IncentiveText';
17
- import { ConnectedSelectFrequency } from './components/SelectFrequency';
18
- import { ConnectedNextUpcomingOrder } from './components/NextUpcomingOrder';
19
- import { ConnectedOffer } from './components/Offer';
20
- import { Modal } from './components/Modal';
21
- import { Select } from './components/Select';
22
- import { Tooltip } from './components/Tooltip';
23
- import { ConnectedFrequencyStatus } from './components/FrequencyStatus';
24
- import * as testMode from './test-mode';
25
- import { api } from './core/api';
26
- import { environment, offer } from './core/reducer';
27
- import { RECEIVE_PRODUCT_PLANS } from './core/constants';
28
- import ConnectedPrice from './components/Price';
29
-
30
- testMode.enable();
31
- let store;
32
-
33
- export const offers = {};
34
-
35
- export function setEnvironment(e) {
36
- store.dispatch(actions.setEnvironment(e));
37
- return offers;
38
- }
39
- export function setMerchantId(m) {
40
- store.dispatch(actions.setMerchantId(m));
41
- return offers;
42
- }
43
- export function setAuthUrl(authUrl) {
44
- store.dispatch(actions.setAuthUrl(authUrl));
45
- return offers;
46
- }
47
- export function getProductsForPurchasePost(productIds = []) {
48
- return adapters.getProductsForPurchasePost(store.getState(), productIds);
49
- }
50
- export function getOptins(productIds = []) {
51
- return adapters.getProductsForPurchasePost(store.getState(), productIds);
52
- }
53
- export function clear() {
54
- store.dispatch(actions.checkout());
55
- }
56
- export function addOptinChangedCallback(fn) {
57
- if (typeof fn === 'function') document.addEventListener('optin-changed', e => fn(e.detail));
58
- }
59
- export function disableOptinChangedCallbacks() {
60
- document.addEventListener('optin-changed', e => e.stopPropagation(), true);
61
- }
62
- export function register() {
63
- try {
64
- customElements.define('og-when', ConnectedWhen);
65
- customElements.define('og-text', ConnectedText);
66
- customElements.define('og-incentive-text', ConnectedIncentiveText);
67
- customElements.define('og-offer', ConnectedOffer);
68
- customElements.define('og-select-frequency', ConnectedSelectFrequency);
69
- customElements.define('og-optout-button', ConnectedOptoutButton);
70
- customElements.define('og-optin-toggle', ConnectedOptinToggle);
71
- customElements.define('og-optin-status', ConnectedOptinStatus);
72
- customElements.define('og-optin-button', ConnectedOptinButton);
73
- customElements.define('og-optin-select', ConnectedOptinSelect);
74
- customElements.define('og-upsell-button', ConnectedUpsellButton);
75
- customElements.define('og-frequency-status', ConnectedFrequencyStatus);
76
- customElements.define('og-modal', Modal);
77
- customElements.define('og-select', Select);
78
- customElements.define('og-tooltip', Tooltip);
79
- customElements.define('og-upsell-modal', ConnectedUpsellModal);
80
- customElements.define('og-next-upcoming-order', ConnectedNextUpcomingOrder);
81
- customElements.define('og-price', ConnectedPrice);
82
- } catch (err) {
83
- // eslint-disable-next-line no-console
84
- console.warn(err);
85
- }
86
- offers.register = () => 0;
87
- }
88
- export function previewMode(set) {
89
- window.og = window.og || {};
90
- if (set === false) {
91
- delete window.og;
92
- } else {
93
- window.og.previewMode = true;
94
- }
95
- return this;
96
- }
97
- export function config(configuration) {
98
- store.dispatch(actions.setConfig(configuration));
99
- return offers;
100
- }
101
- export function setLocale(locale) {
102
- store.dispatch(actions.setLocale(locale));
103
- return offers;
104
- }
105
- export function addTemplate(tagName, content, configOption) {
106
- store.dispatch(actions.addTemplate(tagName, content, configOption));
107
- return offers;
108
- }
109
- /**
110
- * templates object where keys are selectors and values are content
111
- */
112
- export function setTemplates(templates) {
113
- store.dispatch(actions.setTemplates(templates));
114
- return offers;
115
- }
116
- export function setPublicPath(publicPath) {
117
- return offers;
118
- }
119
- export function resolveSettings(merchantId, env, settings, storeInstance = store) {
120
- if (merchantId && env && settings) {
121
- let products = [];
122
- if (settings.product) {
123
- products.push(settings.product);
124
- } else if (settings.cart && Array.isArray(settings.cart.products)) {
125
- products = products.concat(settings.cart.products);
126
- }
127
- const { apiUrl } = environment({}, actions.setEnvironment(env));
128
- const { sessionId } = storeInstance.getState();
129
- if (sessionId) {
130
- products.forEach(product => {
131
- api.fetchOffer(apiUrl, merchantId, sessionId, `${product}`, 'pdp');
132
- });
133
- }
134
-
135
- if (settings.product_discounts && typeof settings.product_discounts === 'object') {
136
- storeInstance.dispatch({ type: RECEIVE_PRODUCT_PLANS, payload: settings.product_discounts });
137
- }
138
- }
139
- }
140
-
141
- /**
142
- * Initialize OG object
143
- * @param {*} merchantId
144
- * @param {*} env
145
- * @param {*} authUrl
1
+ import { makeStore } from './core/store';
2
+ import makeApi from './make-api';
3
+ import defaultReducer from './core/reducer';
4
+ import shopifyReducer from './shopify/shopifyReducer';
5
+ import shopifyMiddleware from './shopify/shopifyMiddleware';
6
+ import platform from './platform';
7
+ import { autoInitializeOffers, onReady } from './core/utils';
8
+ import { authorizeShopifyCustomer } from './shopify/shopifyBootstrap';
9
+
10
+ export const store = makeStore(
11
+ ...(platform?.shopify_selling_plans ? [shopifyReducer, shopifyMiddleware] : [defaultReducer])
12
+ );
13
+
14
+ export const offers = makeApi(store);
15
+
16
+ export const isReady = offers.isReady;
17
+ export const addOptinChangedCallback = offers.addOptinChangedCallback;
18
+ export const addTemplate = offers.addTemplate;
19
+ export const clear = offers.clear;
20
+ export const config = offers.config;
21
+ export const disableOptinChangedCallbacks = offers.disableOptinChangedCallbacks;
22
+ export const getOptins = offers.getOptins;
23
+ export const getProductsForPurchasePost = offers.getProductsForPurchasePost;
24
+ export const initialize = offers.initialize;
25
+ export const previewMode = offers.previewMode;
26
+ export const register = offers.register;
27
+ export const resolveSettings = offers.resolveSettings;
28
+ export const setAuthUrl = offers.setAuthUrl;
29
+ export const setEnvironment = offers.setEnvironment;
30
+ export const setLocale = offers.setLocale;
31
+ export const setMerchantId = offers.setMerchantId;
32
+ export const setPublicPath = offers.setPublicPath;
33
+ export const setTemplates = offers.setTemplates;
34
+ export const setupCart = offers.setupCart;
35
+ export const setupProduct = offers.setupProduct;
36
+ export const setupProducts = offers.setupProducts;
37
+ export { platform };
38
+ export default offers.initialize;
39
+
40
+ /*
41
+ * Attempts to auto initialize the offer library reading the merchantId and env from
42
+ * integration script i.e. <script src="http://static.ordergroove...."/>.
43
+ * Useful when local develop using http redirects
146
44
  */
147
- export function initialize(merchantId, env, authUrl) {
148
- if (offers.isReady) {
149
- console.warn('og.offers has been initialized already. Skipping.');
150
- return offers;
151
- }
152
-
153
- store = getStore();
154
-
155
- offers.store = store;
156
- offers.resolveSettings(merchantId, env, window.og_settings, store);
157
-
158
- setStore(store);
159
-
160
- if (merchantId) offers.setMerchantId(merchantId);
161
- if (env) offers.setEnvironment(env);
162
- if (authUrl) offers.setAuthUrl(authUrl);
45
+ onReady(() => autoInitializeOffers(offers));
163
46
 
164
- window.addEventListener('storage', listenLocalStorageChanges(store));
165
-
166
- if (merchantId && env) {
167
- store.dispatch(actions.requestSessionId());
168
- store.dispatch(actions.fetchAuth());
169
- offers.register();
170
- }
171
-
172
- offers.isReady = true;
173
-
174
- return offers;
47
+ if (platform?.shopify_selling_plans) {
48
+ onReady(() => authorizeShopifyCustomer(offers));
175
49
  }
176
-
177
- export default initialize;
178
-
179
- Object.assign(offers, {
180
- setEnvironment,
181
- setMerchantId,
182
- setAuthUrl,
183
- getProductsForPurchasePost,
184
- getOptins,
185
- clear,
186
- addOptinChangedCallback,
187
- disableOptinChangedCallbacks,
188
- register,
189
- previewMode,
190
- config,
191
- setLocale,
192
- addTemplate,
193
- setTemplates,
194
- setPublicPath,
195
- resolveSettings,
196
- initialize
197
- });
198
-
199
- window.OG = window.OG || {};
200
- Object.assign(window.OG, offers);
201
- Object.assign(offers.initialize, offers);
202
-
203
- offersLiveEditor();
204
-
205
- // // use this syntax to allow es6 module be called as default function og.offers(...)
206
- // module.exports = offers.initialize;
@@ -0,0 +1,195 @@
1
+ import { offersLiveEditor } from '@ordergroove/offers-live-editor';
2
+ import { setStore } from './core/connect';
3
+ import { listenLocalStorageChanges } from './core/localStorage';
4
+ import * as adapters from './core/adapters';
5
+ import * as actions from './core/actions';
6
+ import { ConnectedWhen } from './components/When';
7
+ import { ConnectedOptinButton } from './components/OptinButton';
8
+ import { ConnectedOptoutButton } from './components/OptoutButton';
9
+ import { ConnectedOptinSelect } from './components/OptinSelect';
10
+ import { ConnectedUpsellButton } from './components/UpsellButton';
11
+ import { ConnectedUpsellModal } from './components/UpsellModal';
12
+ import { ConnectedOptinToggle } from './components/OptinToggle';
13
+ import { ConnectedOptinStatus } from './components/OptinStatus';
14
+ import { ConnectedText } from './components/Text';
15
+ import { ConnectedIncentiveText } from './components/IncentiveText';
16
+ import { ConnectedSelectFrequency } from './components/SelectFrequency';
17
+ import { ConnectedNextUpcomingOrder } from './components/NextUpcomingOrder';
18
+ import { ConnectedOffer } from './components/Offer';
19
+ import { Modal } from './components/Modal';
20
+ import { Select } from './components/Select';
21
+ import { Tooltip } from './components/Tooltip';
22
+ import { ConnectedFrequencyStatus } from './components/FrequencyStatus';
23
+ import * as testMode from './test-mode';
24
+ import { api } from './core/api';
25
+ import { environment, offer } from './core/reducer';
26
+ import { DEFAULT_OFFER_MODULE, RECEIVE_PRODUCT_PLANS, SETUP_CART, SETUP_PRODUCT } from './core/constants';
27
+ import ConnectedPrice from './components/Price';
28
+ import { safeProductId } from './core/utils';
29
+
30
+ export default function makeApi(store) {
31
+ testMode.enable();
32
+
33
+ setStore(store);
34
+
35
+ try {
36
+ customElements.define('og-when', ConnectedWhen);
37
+ customElements.define('og-text', ConnectedText);
38
+ customElements.define('og-incentive-text', ConnectedIncentiveText);
39
+ customElements.define('og-offer', ConnectedOffer);
40
+ customElements.define('og-select-frequency', ConnectedSelectFrequency);
41
+ customElements.define('og-optout-button', ConnectedOptoutButton);
42
+ customElements.define('og-optin-toggle', ConnectedOptinToggle);
43
+ customElements.define('og-optin-status', ConnectedOptinStatus);
44
+ customElements.define('og-optin-button', ConnectedOptinButton);
45
+ customElements.define('og-optin-select', ConnectedOptinSelect);
46
+ customElements.define('og-upsell-button', ConnectedUpsellButton);
47
+ customElements.define('og-frequency-status', ConnectedFrequencyStatus);
48
+ customElements.define('og-modal', Modal);
49
+ customElements.define('og-select', Select);
50
+ customElements.define('og-tooltip', Tooltip);
51
+ customElements.define('og-upsell-modal', ConnectedUpsellModal);
52
+ customElements.define('og-next-upcoming-order', ConnectedNextUpcomingOrder);
53
+ customElements.define('og-price', ConnectedPrice);
54
+ } catch (err) {
55
+ console.info('OG WebComponents already registered, skipping.');
56
+ }
57
+
58
+ // // use this syntax to allow es6 module be called as default function og.offers(...)
59
+ // module.exports = offers.initialize;
60
+ let isReady = false;
61
+ const offers = {
62
+ store,
63
+ isReady: () => isReady,
64
+ setEnvironment(e) {
65
+ store.dispatch(actions.setEnvironment(e));
66
+ return this;
67
+ },
68
+ setMerchantId(m) {
69
+ store.dispatch(actions.setMerchantId(m));
70
+ return this;
71
+ },
72
+ setAuthUrl(authUrl) {
73
+ store.dispatch(actions.setAuthUrl(authUrl));
74
+ return this;
75
+ },
76
+ getProductsForPurchasePost(productIds = []) {
77
+ return adapters.getProductsForPurchasePost(store.getState(), productIds);
78
+ },
79
+ getOptins(productIds = []) {
80
+ return adapters.getProductsForPurchasePost(store.getState(), productIds);
81
+ },
82
+ clear() {
83
+ store.dispatch(actions.checkout());
84
+ },
85
+ addOptinChangedCallback(fn) {
86
+ if (typeof fn === 'function') document.addEventListener('optin-changed', e => fn(e.detail));
87
+ },
88
+ disableOptinChangedCallbacks() {
89
+ document.addEventListener('optin-changed', e => e.stopPropagation(), true);
90
+ },
91
+
92
+ register() {
93
+ /* noop */
94
+ },
95
+ previewMode(set) {
96
+ window.og = window.og || {};
97
+ if (set === false) {
98
+ delete window.og;
99
+ } else {
100
+ window.og.previewMode = true;
101
+ }
102
+ return this;
103
+ },
104
+ config(configuration) {
105
+ store.dispatch(actions.setConfig(configuration));
106
+ return this;
107
+ },
108
+ setLocale(locale) {
109
+ store.dispatch(actions.setLocale(locale));
110
+ return this;
111
+ },
112
+ addTemplate(tagName, content, configOption) {
113
+ store.dispatch(actions.addTemplate(tagName, content, configOption));
114
+ return this;
115
+ },
116
+ /**
117
+ * templates object where keys are selectors and values are content
118
+ */
119
+ setTemplates(templates) {
120
+ store.dispatch(actions.setTemplates(templates));
121
+ return this;
122
+ },
123
+
124
+ setPublicPath(publicPath) {
125
+ return this;
126
+ },
127
+
128
+ resolveSettings(merchantId, env, settings, storeInstance = store) {
129
+ if (merchantId && env && settings) {
130
+ let products = [];
131
+ if (settings.product) {
132
+ products.push(settings.product);
133
+ } else if (settings.cart && Array.isArray(settings.cart.products)) {
134
+ products = products.concat(settings.cart.products);
135
+ }
136
+ const { apiUrl } = environment({}, actions.setEnvironment(env));
137
+ const { sessionId } = storeInstance.getState();
138
+ if (sessionId) {
139
+ products.forEach(product => {
140
+ const id = safeProductId(product);
141
+ api.fetchOffer(apiUrl, merchantId, sessionId, `${id}`, DEFAULT_OFFER_MODULE);
142
+ });
143
+ }
144
+
145
+ if (settings.product_discounts && typeof settings.product_discounts === 'object') {
146
+ storeInstance.dispatch({ type: RECEIVE_PRODUCT_PLANS, payload: settings.product_discounts });
147
+ }
148
+ }
149
+ },
150
+
151
+ /**
152
+ * Initialize OG object
153
+ * @param {*} merchantId
154
+ * @param {*} env
155
+ * @param {*} authUrl
156
+ */
157
+ initialize(merchantId, env, authUrl) {
158
+ // settings resolves once, before anything.
159
+ if (!isReady) offers.resolveSettings(merchantId, env, window.og_settings, store);
160
+
161
+ const state = store.getState();
162
+ // dont re-trigger actions if value is the same. allowing set new authurl only
163
+ if (merchantId && merchantId !== state.merchantId) offers.setMerchantId(merchantId);
164
+ if (env && env !== state.environment?.name) offers.setEnvironment(env);
165
+ // allow set new authUrl
166
+ if (authUrl) offers.setAuthUrl(authUrl);
167
+
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
+ isReady = true;
183
+
184
+ return this;
185
+ }
186
+ };
187
+
188
+ window.OG = window.OG || {};
189
+ Object.assign(window.OG, offers);
190
+ Object.assign(offers.initialize, offers);
191
+
192
+ offersLiveEditor();
193
+
194
+ return offers;
195
+ }
@@ -0,0 +1,9 @@
1
+ import { getMainJs } from './core/utils';
2
+
3
+ const script = getMainJs();
4
+
5
+ export default {
6
+ shopify: typeof script?.dataset.shopifySellingPlans !== 'undefined',
7
+ // detect in the frontend if we should use shopify selling plans or not
8
+ shopify_selling_plans: typeof script?.dataset.shopifySellingPlans !== 'undefined'
9
+ };