@ordergroove/offers 2.26.2 → 2.26.3-alpha-PR-593-20.20

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 (48) hide show
  1. package/build.js +3 -1
  2. package/dist/bundle-report.html +170 -104
  3. package/dist/offers.js +64 -75
  4. package/dist/offers.js.map +3 -3
  5. package/examples/cart.js +105 -0
  6. package/examples/index.html +2 -2
  7. package/examples/products/cheap-watch.js +183 -0
  8. package/examples/shopify-cart.html +26 -0
  9. package/examples/shopify-pdp.html +34 -0
  10. package/karma.conf.js +2 -1
  11. package/package.json +4 -4
  12. package/src/__tests__/offers.spec.js +35 -10
  13. package/src/components/FrequencyStatus.js +14 -11
  14. package/src/components/Offer.js +11 -7
  15. package/src/components/OptinButton.js +1 -1
  16. package/src/components/OptinSelect.js +2 -2
  17. package/src/components/OptinToggle.js +2 -2
  18. package/src/components/OptoutButton.js +1 -1
  19. package/src/components/Price.js +8 -4
  20. package/src/components/Select.js +3 -13
  21. package/src/components/SelectFrequency.js +24 -6
  22. package/src/components/TestWizard.js +1 -1
  23. package/src/components/__tests__/OG.fspec.js +24 -0
  24. package/src/components/__tests__/Offer.spec.js +4 -4
  25. package/src/components/__tests__/OptinButton.spec.js +2 -2
  26. package/src/components/__tests__/OptinToggle.spec.js +2 -2
  27. package/src/components/__tests__/OptoutButton.spec.js +1 -1
  28. package/src/components/__tests__/SelectFrequency.fspec.js +1 -0
  29. package/src/components/__tests__/SelectFrequency.spec.js +1 -1
  30. package/src/components/__tests__/TestWizard.spec.js +2 -2
  31. package/src/components/__tests__/Text.spec.js +3 -0
  32. package/src/core/__tests__/actions.spec.js +6 -6
  33. package/src/core/actions.js +12 -10
  34. package/src/core/constants.js +3 -0
  35. package/src/core/reducer.js +14 -14
  36. package/src/core/resolveProperties.js +2 -7
  37. package/src/core/selectors.js +1 -1
  38. package/src/core/store.js +6 -5
  39. package/src/index.js +57 -202
  40. package/src/make-api.js +190 -0
  41. package/src/platform.ts +5 -0
  42. package/src/shopify/__tests__/shopifyReducer.spec.js +477 -0
  43. package/src/shopify/shopifyMiddleware.ts +202 -0
  44. package/src/shopify/shopifyReducer.js +214 -0
  45. package/tsconfig.json +35 -0
  46. package/examples/5starnutrition-main.js +0 -3
  47. package/examples/single-offer.html +0 -9
  48. package/src/init-test.js +0 -3
package/src/index.js CHANGED
@@ -1,206 +1,61 @@
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
146
- */
147
- export function initialize(merchantId, env, authUrl) {
148
- if (offers.isReady) {
149
- console.warn('og.offers has been initialized already. Skipping.');
150
- return offers;
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
+
8
+ export const store = makeStore(
9
+ ...(platform.shopify_selling_plans ? [shopifyReducer, shopifyMiddleware] : [defaultReducer])
10
+ );
11
+
12
+ export const offers = makeApi(store);
13
+
14
+ export const isReady = offers.isReady;
15
+ export const addOptinChangedCallback = offers.addOptinChangedCallback;
16
+ export const addTemplate = offers.addTemplate;
17
+ export const clear = offers.clear;
18
+ export const config = offers.config;
19
+ export const disableOptinChangedCallbacks = offers.disableOptinChangedCallbacks;
20
+ export const getOptins = offers.getOptins;
21
+ export const getProductsForPurchasePost = offers.getProductsForPurchasePost;
22
+ export const initialize = offers.initialize;
23
+ export const previewMode = offers.previewMode;
24
+ export const register = offers.register;
25
+ export const resolveSettings = offers.resolveSettings;
26
+ export const setAuthUrl = offers.setAuthUrl;
27
+ export const setEnvironment = offers.setEnvironment;
28
+ export const setLocale = offers.setLocale;
29
+ export const setMerchantId = offers.setMerchantId;
30
+ export const setPublicPath = offers.setPublicPath;
31
+ export const setTemplates = offers.setTemplates;
32
+ export const setupCart = offers.setupCart;
33
+ export const setupProduct = offers.setupProduct;
34
+ export const setupProducts = offers.setupProducts;
35
+
36
+ export default offers.initialize;
37
+
38
+ (function autoInitializeOffers() {
39
+ /*
40
+ * Attempts to auto initialize the offer library reading the merchantId and env from
41
+ * integration script i.e. <script src="http://static.ordergroove...."/>.
42
+ * Useful when local develop using http redirects
43
+ */
44
+ if (document.readyState === 'loading') {
45
+ window.addEventListener('DOMContentLoaded', autoInitializeOffers);
46
+ return;
151
47
  }
48
+ if (isReady()) return;
49
+ const script = document.querySelector(
50
+ 'script[src^="https://static.ordergroove"],script[src^="https://staging.static.ordergroove"]'
51
+ );
52
+ if (!script) return;
152
53
 
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);
163
-
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;
175
- }
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);
54
+ const url = new URL(script.src);
55
+ const env = url.host.startsWith('staging') ? 'staging' : 'prod';
56
+ const merchantId = url.pathname.split('/')[1];
202
57
 
203
- offersLiveEditor();
58
+ if (!env && !merchantId) return;
204
59
 
205
- // // use this syntax to allow es6 module be called as default function og.offers(...)
206
- // module.exports = offers.initialize;
60
+ initialize(merchantId, env);
61
+ })();
@@ -0,0 +1,190 @@
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
+
29
+ try {
30
+ customElements.define('og-when', ConnectedWhen);
31
+ customElements.define('og-text', ConnectedText);
32
+ customElements.define('og-incentive-text', ConnectedIncentiveText);
33
+ customElements.define('og-offer', ConnectedOffer);
34
+ customElements.define('og-select-frequency', ConnectedSelectFrequency);
35
+ customElements.define('og-optout-button', ConnectedOptoutButton);
36
+ customElements.define('og-optin-toggle', ConnectedOptinToggle);
37
+ customElements.define('og-optin-status', ConnectedOptinStatus);
38
+ customElements.define('og-optin-button', ConnectedOptinButton);
39
+ customElements.define('og-optin-select', ConnectedOptinSelect);
40
+ customElements.define('og-upsell-button', ConnectedUpsellButton);
41
+ customElements.define('og-frequency-status', ConnectedFrequencyStatus);
42
+ customElements.define('og-modal', Modal);
43
+ customElements.define('og-select', Select);
44
+ customElements.define('og-tooltip', Tooltip);
45
+ customElements.define('og-upsell-modal', ConnectedUpsellModal);
46
+ customElements.define('og-next-upcoming-order', ConnectedNextUpcomingOrder);
47
+ customElements.define('og-price', ConnectedPrice);
48
+ } catch (err) {
49
+ console.info('OG WebComponents already registered, skipping.');
50
+ }
51
+
52
+ export default function makeApi(store) {
53
+ testMode.enable();
54
+
55
+ setStore(store);
56
+
57
+ // // use this syntax to allow es6 module be called as default function og.offers(...)
58
+ // module.exports = offers.initialize;
59
+ let isReady = false;
60
+ const offers = {
61
+ store,
62
+ isReady: () => isReady,
63
+ setEnvironment(e) {
64
+ store.dispatch(actions.setEnvironment(e));
65
+ return this;
66
+ },
67
+ setMerchantId(m) {
68
+ store.dispatch(actions.setMerchantId(m));
69
+ return this;
70
+ },
71
+ setAuthUrl(authUrl) {
72
+ store.dispatch(actions.setAuthUrl(authUrl));
73
+ return this;
74
+ },
75
+ getProductsForPurchasePost(productIds = []) {
76
+ return adapters.getProductsForPurchasePost(store.getState(), productIds);
77
+ },
78
+ getOptins(productIds = []) {
79
+ return adapters.getProductsForPurchasePost(store.getState(), productIds);
80
+ },
81
+ clear() {
82
+ store.dispatch(actions.checkout());
83
+ },
84
+ addOptinChangedCallback(fn) {
85
+ if (typeof fn === 'function') document.addEventListener('optin-changed', e => fn(e.detail));
86
+ },
87
+ disableOptinChangedCallbacks() {
88
+ document.addEventListener('optin-changed', e => e.stopPropagation(), true);
89
+ },
90
+
91
+ register() {
92
+ /* noop */
93
+ },
94
+ previewMode(set) {
95
+ window.og = window.og || {};
96
+ if (set === false) {
97
+ delete window.og;
98
+ } else {
99
+ window.og.previewMode = true;
100
+ }
101
+ return this;
102
+ },
103
+ config(configuration) {
104
+ store.dispatch(actions.setConfig(configuration));
105
+ return this;
106
+ },
107
+ setLocale(locale) {
108
+ store.dispatch(actions.setLocale(locale));
109
+ return this;
110
+ },
111
+ addTemplate(tagName, content, configOption) {
112
+ store.dispatch(actions.addTemplate(tagName, content, configOption));
113
+ return this;
114
+ },
115
+ /**
116
+ * templates object where keys are selectors and values are content
117
+ */
118
+ setTemplates(templates) {
119
+ store.dispatch(actions.setTemplates(templates));
120
+ return this;
121
+ },
122
+
123
+ setPublicPath(publicPath) {
124
+ return this;
125
+ },
126
+
127
+ resolveSettings(merchantId, env, settings, storeInstance = store) {
128
+ if (merchantId && env && settings) {
129
+ let products = [];
130
+ if (settings.product) {
131
+ products.push(settings.product);
132
+ } else if (settings.cart && Array.isArray(settings.cart.products)) {
133
+ products = products.concat(settings.cart.products);
134
+ }
135
+ const { apiUrl } = environment({}, actions.setEnvironment(env));
136
+ const { sessionId } = storeInstance.getState();
137
+ if (sessionId) {
138
+ products.forEach(product => {
139
+ api.fetchOffer(apiUrl, merchantId, sessionId, `${product}`, DEFAULT_OFFER_MODULE);
140
+ });
141
+ }
142
+
143
+ if (settings.product_discounts && typeof settings.product_discounts === 'object') {
144
+ storeInstance.dispatch({ type: RECEIVE_PRODUCT_PLANS, payload: settings.product_discounts });
145
+ }
146
+ }
147
+ },
148
+
149
+ /**
150
+ * Initialize OG object
151
+ * @param {*} merchantId
152
+ * @param {*} env
153
+ * @param {*} authUrl
154
+ */
155
+ initialize(merchantId, env, authUrl) {
156
+ // settings resolves once, before anything.
157
+ if (!isReady) offers.resolveSettings(merchantId, env, window.og_settings, store);
158
+
159
+ const state = store.getState();
160
+ // dont re-trigger actions if value is the same. allowing set new authurl only
161
+ if (merchantId && merchantId !== state.merchantId) offers.setMerchantId(merchantId);
162
+ if (env && env !== state.environment?.name) offers.setEnvironment(env);
163
+ // allow set new authUrl
164
+ if (authUrl) offers.setAuthUrl(authUrl);
165
+
166
+ if (isReady) {
167
+ console.warn('og.offers has been initialized already. Skipping.');
168
+ } else {
169
+ window.addEventListener('storage', listenLocalStorageChanges(store));
170
+ }
171
+
172
+ if (arguments.length === 3) {
173
+ store.dispatch(actions.requestSessionId());
174
+ store.dispatch(actions.fetchAuth());
175
+ }
176
+
177
+ isReady = true;
178
+
179
+ return this;
180
+ }
181
+ };
182
+
183
+ window.OG = window.OG || {};
184
+ Object.assign(window.OG, offers);
185
+ Object.assign(offers.initialize, offers);
186
+
187
+ offersLiveEditor();
188
+
189
+ return offers;
190
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ shopify: !!window.Shopify,
3
+ // detect in the frontend if we should use shopify selling plans or not
4
+ shopify_selling_plans: !!window.Shopify
5
+ };