@ordergroove/offers 2.30.2 → 2.30.4-alpha-PR-716-2.14

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.
@@ -114,6 +114,7 @@
114
114
  <option>upsell</option>
115
115
  <option>subscribed</option>
116
116
  <option>not-subscribed</option>
117
+ <option>prepaid</option>
117
118
  </select>
118
119
 
119
120
  <div id="the-offer">
package/examples/index.js CHANGED
@@ -8,24 +8,24 @@ import { getMarkup, getStyles } from '@ordergroove/offers-templates';
8
8
  window.og_settings = {
9
9
  // object were key is product id and value is an array of plan discount
10
10
  product_discounts: {
11
- UD729: {
11
+ UD728: {
12
12
  '3_1': ['30.00', '10%', '$27.00'],
13
13
  '1_2': ['30.00', '20%', '$24.00']
14
14
  },
15
- UD728: [
15
+ UD729: [
16
16
  {
17
- frequency: '1_2',
18
- prepaidShipments: '3',
17
+ frequency: '1_3',
18
+ prepaidShipments: null,
19
19
  regularPrice: '$15.00',
20
20
  subscriptionPrice: '$13.50',
21
21
  discountRate: '10%'
22
22
  },
23
23
  {
24
- frequency: '3_1',
24
+ frequency: '2_3',
25
25
  prepaidShipments: null,
26
26
  regularPrice: '$15.00',
27
- subscriptionPrice: '$12.00',
28
- discountRate: '20%'
27
+ subscriptionPrice: '$13.50',
28
+ discountRate: '10%'
29
29
  }
30
30
  ]
31
31
  }
@@ -179,7 +179,8 @@ const offersExamples = [
179
179
  },
180
180
  {
181
181
  name: 'Prepaid',
182
- selector: 'og-offer[location="initial"]',
182
+ defaultPreviewMode: 'prepaid',
183
+ selector: 'og-offer[location="prepaid-pdp"]',
183
184
  config: {
184
185
  settings: {
185
186
  ...settings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/offers",
3
- "version": "2.30.2",
3
+ "version": "2.30.4-alpha-PR-716-2.14+6c203a6e",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -45,7 +45,7 @@
45
45
  "throttle-debounce": "^2.1.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@ordergroove/offers-templates": "^0.5.1"
48
+ "@ordergroove/offers-templates": "^0.5.2"
49
49
  },
50
- "gitHead": "81e7eb5ad4aabc79a35df89c936632c8f422d7d5"
50
+ "gitHead": "6c203a6e6da4957fde333448b676e1584ef4c685"
51
51
  }
@@ -64,6 +64,7 @@ export class Offer extends TemplateElement {
64
64
  if (preview === 'preview-standard-offer') this.preview = 'regular';
65
65
  else if (preview === 'preview-upsell-offer') this.preview = 'upsell';
66
66
  else if (preview === 'preview-subscribed-offer') this.preview = 'subscribed';
67
+ else if (preview === 'preview-prepaid-offer') this.preview = 'prepaid';
67
68
  }
68
69
 
69
70
  static get styles() {
@@ -0,0 +1,187 @@
1
+ import { mergeProductPlansToState } from '../actions-preview';
2
+
3
+ describe('actions preview', () => {
4
+ describe('mergeProductPlansToState', () => {
5
+ it('Should merge productPlans to state correctly', () => {
6
+ const payAsYouGoPlan = [
7
+ {
8
+ frequency: '3_1',
9
+ prepaidShipments: null,
10
+ regularPrice: '30.00',
11
+ subscriptionPrice: '$27.00',
12
+ discountRate: '10%'
13
+ },
14
+ {
15
+ frequency: '1_2',
16
+ prepaidShipments: null,
17
+ regularPrice: '30.00',
18
+ subscriptionPrice: '$24.00',
19
+ discountRate: '20%'
20
+ }
21
+ ];
22
+
23
+ const payAsYouGoThat2 = [
24
+ {
25
+ frequency: '1_3',
26
+ prepaidShipments: null,
27
+ regularPrice: '$15.00',
28
+ subscriptionPrice: '$13.50',
29
+ discountRate: '10%'
30
+ },
31
+ {
32
+ frequency: '2_3',
33
+ prepaidShipments: null,
34
+ regularPrice: '$15.00',
35
+ subscriptionPrice: '$13.50',
36
+ discountRate: '10%'
37
+ }
38
+ ];
39
+
40
+ const prepaidPlansToBeAdded = [
41
+ {
42
+ frequency: '1_3',
43
+ regularPrice: '$15.00',
44
+ subscriptionPrice: '$12.00',
45
+ discountRate: '25%',
46
+ prepaidShipments: 3,
47
+ regularPrepaidPrice: '$36.00',
48
+ prepaidSavingsPerShipment: '$3.00',
49
+ prepaidSavingsTotal: '$9.00',
50
+ prepaidExtraSavingsPercentage: '10%'
51
+ },
52
+ {
53
+ frequency: '1_3',
54
+ regularPrice: '$15.00',
55
+ subscriptionPrice: '$12.00',
56
+ discountRate: '20%',
57
+ prepaidShipments: 6,
58
+ regularPrepaidPrice: '$72.00',
59
+ prepaidSavingsPerShipment: '$3.00',
60
+ prepaidSavingsTotal: '$18.00',
61
+ prepaidExtraSavingsPercentage: '10%'
62
+ },
63
+ {
64
+ frequency: '1_3',
65
+ regularPrice: '$15.00',
66
+ subscriptionPrice: '$12.00',
67
+ discountRate: '20%',
68
+ prepaidShipments: 12,
69
+ regularPrepaidPrice: '$144.00',
70
+ prepaidSavingsPerShipment: '$3.00',
71
+ prepaidSavingsTotal: '$36.00',
72
+ prepaidExtraSavingsPercentage: '10%'
73
+ }
74
+ ];
75
+
76
+ const state = {
77
+ UD728: payAsYouGoPlan,
78
+ UD729: payAsYouGoThat2,
79
+ UD730: [
80
+ {
81
+ frequency: '1_2',
82
+ prepaidShipments: null,
83
+ regularPrice: '30.00',
84
+ subscriptionPrice: '$24.00',
85
+ discountRate: '20%'
86
+ }
87
+ ]
88
+ };
89
+
90
+ const repeatedProductPlan = {
91
+ frequency: '3_1',
92
+ prepaidShipments: null,
93
+ regularPrice: '30.00',
94
+ subscriptionPrice: '$27.00',
95
+ discountRate: '10%'
96
+ };
97
+
98
+ const differentProductPlan = {
99
+ frequency: '1_2',
100
+ prepaidShipments: null,
101
+ regularPrice: '30.00',
102
+ subscriptionPrice: '$24.00',
103
+ discountRate: '21%'
104
+ };
105
+
106
+ const productPlans = {
107
+ UD728: [repeatedProductPlan],
108
+ UD729: prepaidPlansToBeAdded,
109
+ UD730: [differentProductPlan]
110
+ };
111
+
112
+ const expected = {
113
+ UD728: [...payAsYouGoPlan],
114
+ UD729: [...payAsYouGoThat2, ...prepaidPlansToBeAdded],
115
+ UD730: [
116
+ {
117
+ frequency: '1_2',
118
+ prepaidShipments: null,
119
+ regularPrice: '30.00',
120
+ subscriptionPrice: '$24.00',
121
+ discountRate: '20%'
122
+ },
123
+ {
124
+ frequency: '1_2',
125
+ prepaidShipments: null,
126
+ regularPrice: '30.00',
127
+ subscriptionPrice: '$24.00',
128
+ discountRate: '21%'
129
+ }
130
+ ]
131
+ };
132
+
133
+ expect(mergeProductPlansToState(state, productPlans)).toEqual(expected);
134
+ });
135
+
136
+ it('Should not add anything if productPlans are equal to state', () => {
137
+ const prepaidPlans = [
138
+ {
139
+ frequency: '1_3',
140
+ regularPrice: '$15.00',
141
+ subscriptionPrice: '$12.00',
142
+ discountRate: '25%',
143
+ prepaidShipments: 3,
144
+ regularPrepaidPrice: '$36.00',
145
+ prepaidSavingsPerShipment: '$3.00',
146
+ prepaidSavingsTotal: '$9.00',
147
+ prepaidExtraSavingsPercentage: '10%'
148
+ },
149
+ {
150
+ frequency: '1_3',
151
+ regularPrice: '$15.00',
152
+ subscriptionPrice: '$12.00',
153
+ discountRate: '20%',
154
+ prepaidShipments: 6,
155
+ regularPrepaidPrice: '$72.00',
156
+ prepaidSavingsPerShipment: '$3.00',
157
+ prepaidSavingsTotal: '$18.00',
158
+ prepaidExtraSavingsPercentage: '10%'
159
+ },
160
+ {
161
+ frequency: '1_3',
162
+ regularPrice: '$15.00',
163
+ subscriptionPrice: '$12.00',
164
+ discountRate: '20%',
165
+ prepaidShipments: 12,
166
+ regularPrepaidPrice: '$144.00',
167
+ prepaidSavingsPerShipment: '$3.00',
168
+ prepaidSavingsTotal: '$36.00',
169
+ prepaidExtraSavingsPercentage: '10%'
170
+ }
171
+ ];
172
+ const state = {
173
+ UD729: prepaidPlans
174
+ };
175
+
176
+ const productPlans = {
177
+ UD729: prepaidPlans
178
+ };
179
+
180
+ const expected = {
181
+ UD729: prepaidPlans
182
+ };
183
+
184
+ expect(mergeProductPlansToState(state, productPlans)).toEqual(expected);
185
+ });
186
+ });
187
+ });
@@ -1,4 +1,5 @@
1
- import { receiveOffer, receiveOrders, authorize, unauthorized, optinProduct, optoutProduct } from './actions';
1
+ import { receiveOffer, receiveOrders, authorize, unauthorized, optinProduct } from './actions';
2
+ import { getObjectStructuredProductPlans } from './adapters';
2
3
  import * as constants from './constants';
3
4
 
4
5
  export const setPreviewStandardOffer = (isPreview, productId, offer) =>
@@ -62,6 +63,19 @@ export const setPreviewStandardOffer = (isPreview, productId, offer) =>
62
63
  );
63
64
  };
64
65
 
66
+ export const mergeProductPlansToState = (state, newProductPlans) => {
67
+ Object.entries(newProductPlans).forEach(([key, value]) => {
68
+ if (Object.prototype.hasOwnProperty.call(state, key)) {
69
+ const mergedArray = state[key].concat(value);
70
+ const uniqueArray = [...new Set(mergedArray.map(item => JSON.stringify(item)))];
71
+ state[key] = uniqueArray.map(item => JSON.parse(item));
72
+ } else {
73
+ state[key] = value;
74
+ }
75
+ });
76
+ return state;
77
+ };
78
+
65
79
  export const setPreviewUpsellOffer = (isPreview, productId, offer) =>
66
80
  async function setPreviewUpsellOfferThunk(dispatch, getState) {
67
81
  await dispatch({ type: constants.SET_PREVIEW_UPSELL_OFFER, payload: isPreview });
@@ -122,6 +136,133 @@ export const setPreviewUpsellOffer = (isPreview, productId, offer) =>
122
136
  }
123
137
  };
124
138
 
139
+ export const setPreviewPrepaid = (isPreview, productId, offer) =>
140
+ async function setPreviewPrepaidThunk(dispatch, getState) {
141
+ const existingProductPlans = getState().productPlans;
142
+
143
+ await dispatch({
144
+ type: constants.SET_PREVIEW_PREPAID_OFFER,
145
+ payload: isPreview
146
+ });
147
+ await dispatch({
148
+ type: constants.UNAUTHORIZED
149
+ });
150
+ await dispatch(
151
+ receiveOffer(
152
+ {
153
+ in_stock: { [productId]: true },
154
+ eligibility_groups: { [productId]: ['subscription', 'upsell', 'prepaid'] },
155
+ result: 'success',
156
+ autoship: { [productId]: true },
157
+ autoship_by_default: { [productId]: false },
158
+ modifiers: {},
159
+ module_view: { regular: '096135e6650111e9a444bc764e106cf4' },
160
+ incentives_display: {
161
+ '47c01e9aacbe40389b5c7325d79091aa': {
162
+ field: 'sub_total',
163
+ object: 'order',
164
+ type: 'Discount Percent',
165
+ value: 5
166
+ },
167
+ e6534b9d877f41e586c37b7d8abc3a58: {
168
+ field: 'total_price',
169
+ object: 'item',
170
+ type: 'Discount Percent',
171
+ value: 10
172
+ },
173
+ f35e842710b24929922db4a529eecd40: {
174
+ field: 'total_price',
175
+ object: 'item',
176
+ type: 'Discount Percent',
177
+ value: 10
178
+ },
179
+ '5be321d7c17f4e18a757212b9a20bfcc': {
180
+ field: 'total_price',
181
+ object: 'item',
182
+ type: 'Discount Percent',
183
+ value: 1
184
+ }
185
+ },
186
+ incentives: {
187
+ [productId]: {
188
+ initial: ['5be321d7c17f4e18a757212b9a20bfcc'],
189
+ ongoing: [
190
+ 'e6534b9d877f41e586c37b7d8abc3a58',
191
+ '47c01e9aacbe40389b5c7325d79091aa',
192
+ 'f35e842710b24929922db4a529eecd40'
193
+ ]
194
+ }
195
+ }
196
+ },
197
+ offer
198
+ )
199
+ );
200
+ await dispatch({
201
+ type: constants.RECEIVE_PRODUCT_PLANS,
202
+ payload: mergeProductPlansToState(
203
+ existingProductPlans,
204
+ getObjectStructuredProductPlans({
205
+ [productId]: [
206
+ {
207
+ frequency: '1_3',
208
+ regularPrice: '$15.00',
209
+ subscriptionPrice: '$12.00',
210
+ discountRate: '25%',
211
+ prepaidShipments: 3,
212
+ regularPrepaidPrice: '$36.00',
213
+ prepaidSavingsPerShipment: '$3.00',
214
+ prepaidSavingsTotal: '$9.00',
215
+ prepaidExtraSavingsPercentage: '10%'
216
+ },
217
+ {
218
+ frequency: '1_3',
219
+ regularPrice: '$15.00',
220
+ subscriptionPrice: '$12.00',
221
+ discountRate: '20%',
222
+ prepaidShipments: 6,
223
+ regularPrepaidPrice: '$72.00',
224
+ prepaidSavingsPerShipment: '$3.00',
225
+ prepaidSavingsTotal: '$18.00',
226
+ prepaidExtraSavingsPercentage: '10%'
227
+ },
228
+ {
229
+ frequency: '1_3',
230
+ regularPrice: '$15.00',
231
+ subscriptionPrice: '$12.00',
232
+ discountRate: '20%',
233
+ prepaidShipments: 12,
234
+ regularPrepaidPrice: '$144.00',
235
+ prepaidSavingsPerShipment: '$3.00',
236
+ prepaidSavingsTotal: '$36.00',
237
+ prepaidExtraSavingsPercentage: '10%'
238
+ }
239
+ ]
240
+ })
241
+ )
242
+ });
243
+ await dispatch({
244
+ type: constants.SET_CONFIG,
245
+ payload: {
246
+ prepaidSellingPlans: {
247
+ [productId]: [
248
+ {
249
+ numberShipments: 3,
250
+ sellingPlan: '1_3'
251
+ },
252
+ {
253
+ numberShipments: 6,
254
+ sellingPlan: '1_3'
255
+ },
256
+ {
257
+ numberShipments: 12,
258
+ sellingPlan: '1_3'
259
+ }
260
+ ]
261
+ }
262
+ }
263
+ });
264
+ };
265
+
125
266
  export const setPreview = (value, oldValue, offer) =>
126
267
  async function(dispatch, getState) {
127
268
  await dispatch({ type: constants.LOCAL_STORAGE_CLEAR });
@@ -145,6 +286,11 @@ export const setPreview = (value, oldValue, offer) =>
145
286
  dispatch(setPreviewStandardOffer(true, offer.product.id, offer));
146
287
  dispatch(optinProduct(offer.product, '2_2'));
147
288
  break;
289
+ case 'prepaid':
290
+ dispatch(setPreviewPrepaid(true, offer.product.id, offer));
291
+ // Prepaid needs to be subscribed to appear
292
+ dispatch(optinProduct(offer.product, '1_3'));
293
+ break;
148
294
  default:
149
295
  }
150
296
  };
@@ -31,6 +31,7 @@ export const SET_LOCALE = 'SET_LOCALE';
31
31
  export const SET_CONFIG = 'SET_CONFIG';
32
32
  export const SET_PREVIEW_STANDARD_OFFER = 'SET_PREVIEW_STANDARD_OFFER';
33
33
  export const SET_PREVIEW_UPSELL_OFFER = 'SET_PREVIEW_UPSELL_OFFER';
34
+ export const SET_PREVIEW_PREPAID_OFFER = 'SET_PREVIEW_PREPAID_OFFER';
34
35
  export const ADD_TEMPLATE = 'ADD_TEMPLATE';
35
36
  export const SET_TEMPLATES = 'SET_TEMPLATES';
36
37
  export const LOCAL_STORAGE_CHANGE = 'LOCAL_STORAGE_CHANGE';
@@ -420,6 +420,15 @@ export const previewUpsellOffer = (state = false, action) => {
420
420
  }
421
421
  };
422
422
 
423
+ export const previewPrepaidOffer = (state = false, action) => {
424
+ switch (action.type) {
425
+ case constants.SET_PREVIEW_PREPAID_OFFER:
426
+ return action.payload;
427
+ default:
428
+ return state;
429
+ }
430
+ };
431
+
423
432
  export const autoshipByDefault = (state = [], action) => {
424
433
  switch (action.type) {
425
434
  case constants.RECEIVE_OFFER:
@@ -27,14 +27,15 @@ const PRODUCTS_URL = `${SHOPIFY_ROOT}products/`;
27
27
  */
28
28
  const DEFAULT_SHOPIFY_CART_AJAX_SECTIONS =
29
29
  '[id^="shopify-section-"][id$=__cart-items], [id^="shopify-section-"][id$="__cart-footer"],#cart-live-region-text,#cart-icon-bubble';
30
- const syncProductId = debounce(100, false, function(form, offer) {
31
- const { id } = Object.fromEntries([...new FormData(form).entries()]);
32
- if (id) {
33
- offer.setAttribute('product', id);
34
- } else {
35
- offer.removeAttribute('product');
36
- }
37
- });
30
+ const makeSyncProductId = offer =>
31
+ debounce(100, false, function(form) {
32
+ const { id } = Object.fromEntries([...new FormData(form).entries()]);
33
+ if (id) {
34
+ offer.setAttribute('product', id);
35
+ } else {
36
+ offer.removeAttribute('product');
37
+ }
38
+ });
38
39
 
39
40
  async function setupPdp(store, offer) {
40
41
  const handle = guessProductHandle(offer);
@@ -48,7 +49,6 @@ async function setupPdp(store, offer) {
48
49
  }
49
50
  // try closest form (safer)
50
51
  let form = offer.closest('form');
51
-
52
52
  // sometimes template is so closest does not work
53
53
  // <div>
54
54
  // <og-offer ..>
@@ -69,8 +69,9 @@ async function setupPdp(store, offer) {
69
69
 
70
70
  if (form) {
71
71
  // since syncProductId is debounced not matter which comes first mutation or onchange
72
- form.addEventListener('change', ev => syncProductId(form, offer));
73
- const mo = new MutationObserver(() => syncProductId(form, offer));
72
+ const syncProductId = makeSyncProductId(offer);
73
+ form.addEventListener('change', ev => syncProductId(form));
74
+ const mo = new MutationObserver(() => syncProductId(form));
74
75
  mo.observe(form, { subtree: true, childList: true });
75
76
  } else {
76
77
  console.info('no /cart/add form found for og-offer', offer);