@ordergroove/offers 2.26.9 → 2.27.0
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.
- package/CHANGELOG.md +39 -0
- package/README.md +34 -0
- package/build.js +3 -1
- package/dist/bundle-report.html +186 -117
- package/dist/examples.js +18 -3
- package/dist/examples.js.map +1 -1
- package/dist/offers.js +65 -76
- package/dist/offers.js.map +3 -3
- package/examples/cart.js +105 -0
- package/examples/index.html +2 -2
- package/examples/products/cheap-watch.js +183 -0
- package/examples/shopify-cart.html +26 -0
- package/examples/shopify-pdp.html +34 -0
- package/karma.conf.js +2 -1
- package/package.json +5 -5
- package/src/__tests__/offers.spec.js +35 -10
- package/src/components/FrequencyStatus.js +14 -11
- package/src/components/IncentiveText.js +2 -1
- package/src/components/Offer.js +14 -7
- package/src/components/OptinButton.js +1 -1
- package/src/components/OptinSelect.js +2 -2
- package/src/components/OptinToggle.js +2 -2
- package/src/components/OptoutButton.js +1 -1
- package/src/components/Price.js +8 -4
- package/src/components/Select.js +3 -13
- package/src/components/SelectFrequency.js +24 -6
- package/src/components/TestWizard.js +1 -1
- package/src/components/__tests__/OG.fspec.js +24 -0
- package/src/components/__tests__/Offer.spec.js +4 -4
- package/src/components/__tests__/OptinButton.spec.js +2 -2
- package/src/components/__tests__/OptinToggle.spec.js +2 -2
- package/src/components/__tests__/OptoutButton.spec.js +1 -1
- package/src/components/__tests__/SelectFrequency.fspec.js +1 -0
- package/src/components/__tests__/SelectFrequency.spec.js +1 -1
- package/src/components/__tests__/TestWizard.spec.js +2 -2
- package/src/components/__tests__/Text.spec.js +5 -1
- package/src/core/__tests__/actions.spec.js +6 -6
- package/src/core/actions.js +22 -17
- package/src/core/constants.js +21 -0
- package/src/core/descriptors.js +2 -1
- package/src/core/middleware.js +41 -1
- package/src/core/reducer.js +22 -21
- package/src/core/resolveProperties.js +2 -7
- package/src/core/selectors.js +1 -1
- package/src/core/store.js +17 -9
- package/src/core/utils.ts +67 -0
- package/src/index.js +46 -203
- package/src/make-api.js +195 -0
- package/src/platform.ts +9 -0
- package/src/shopify/__tests__/shopifyMiddleware.spec.js +126 -0
- package/src/shopify/__tests__/shopifyReducer.spec.js +489 -0
- package/src/shopify/shopifyBootstrap.ts +136 -0
- package/src/shopify/shopifyMiddleware.ts +336 -0
- package/src/shopify/shopifyReducer.js +254 -0
- package/tsconfig.json +35 -0
- package/examples/5starnutrition-main.js +0 -3
- package/examples/single-offer.html +0 -9
- 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
|
-
|
|
112
|
-
super.connectedCallback && super.connectedCallback();
|
|
107
|
+
return { options, isSelected };
|
|
113
108
|
}
|
|
114
109
|
};
|
package/src/core/selectors.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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 {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
export const
|
|
34
|
-
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/src/make-api.js
ADDED
|
@@ -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
|
+
}
|
package/src/platform.ts
ADDED
|
@@ -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
|
+
};
|