@ordergroove/offers 2.28.7-alpha-PR-690-14.11 → 2.28.7

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.
@@ -76,8 +76,6 @@
76
76
  --og-tooltip-size: 10px;
77
77
  --og-tooltip-color: rgba(245, 166, 35, 1);
78
78
 
79
- --og-checkbox-border-color: #000000;
80
-
81
79
  --og-upsell-background: rgba(202, 25, 148, 1);
82
80
  --og-upsell-family: Arial, Helvetica, sans-serif;
83
81
  --og-upsell-size: 13px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/offers",
3
- "version": "2.28.7-alpha-PR-690-14.11+6ec39a1d",
3
+ "version": "2.28.7",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -47,5 +47,5 @@
47
47
  "devDependencies": {
48
48
  "@ordergroove/offers-templates": "^0.4.19"
49
49
  },
50
- "gitHead": "6ec39a1d1a4cd1426566006c5be41be68b030978"
50
+ "gitHead": "20dc90b04c6796d7374cde6375228faf3a8108e1"
51
51
  }
@@ -53,12 +53,6 @@ export class OptinStatus extends withProduct(TemplateElement) {
53
53
  .checkbox {
54
54
  border-radius: 3px;
55
55
  }
56
-
57
- .radio,
58
- .checkbox {
59
- border-color: var(--og-checkbox-border-color, black);
60
- }
61
-
62
56
  .checkbox.active::after,
63
57
  .radio.active::after {
64
58
  position: absolute;
@@ -67,12 +61,12 @@ export class OptinStatus extends withProduct(TemplateElement) {
67
61
  width: 100%;
68
62
  height: 100%;
69
63
  box-sizing: border-box;
70
- background: var(--og-checkbox-border-color, black);
71
64
  }
72
65
 
73
66
  .radio.active::after {
74
67
  content: ' ';
75
68
  border-radius: 100%;
69
+ background: var(--og-primary-color, var(--og-radio-background-color, black));
76
70
  border: 2px solid #fff;
77
71
  }
78
72
 
@@ -81,6 +75,7 @@ export class OptinStatus extends withProduct(TemplateElement) {
81
75
  border-radius: 0;
82
76
  background: #fff;
83
77
  content: '\\2714';
78
+ color: var(--og-primary-color, var(--og-checkbox-color, black));
84
79
  line-height: 1;
85
80
  text-align: center;
86
81
  overflow: visible;
@@ -25,7 +25,7 @@ export class OptinToggle extends OptinStatus {
25
25
  height: var(--og-radio-height, 1.4em);
26
26
  margin: var(--og-radio-margin, 0);
27
27
  padding: 0;
28
- border: 1px solid var(--og-checkbox-border-color, black);
28
+ border: 1px solid var(--og-primary-color, black);
29
29
  background: #fff;
30
30
  vertical-align: middle;
31
31
  color: var(--og-primary-color, black);
@@ -36,7 +36,7 @@ export class OptinToggle extends OptinStatus {
36
36
  }
37
37
 
38
38
  .btn.active {
39
- background: var(--og-checkbox-border-color, black);
39
+ background: #090909;
40
40
  }
41
41
 
42
42
  .btn.active:after {
@@ -1,6 +1,7 @@
1
1
  import fetchMock from 'fetch-mock';
2
2
  import { CART_UPDATED_EVENT, OPTIN_PRODUCT, SETUP_CART } from '../../core/constants';
3
- import { getOrCreateHidden, synchronizeCartOptin } from '../shopifyMiddleware';
3
+ import { synchronizeCartOptin, getTrackingEvent } from '../shopifyMiddleware';
4
+ import { getOrCreateHidden } from '../../core/utils';
4
5
 
5
6
  function makeForm(addInput = true) {
6
7
  const element = document.createElement('form');
@@ -43,6 +44,46 @@ describe('getOrCreateHidden', () => {
43
44
  });
44
45
  });
45
46
 
47
+ describe('getTrackingEvent', () => {
48
+ const keyRegex = new RegExp('og__[0-9]+');
49
+ it('make tracking event for optout', () => {
50
+ const actionIn = {
51
+ type: 'OPTOUT_PRODUCT',
52
+ payload: {
53
+ product: {
54
+ id: 'testProduct'
55
+ },
56
+ offer: {
57
+ location: 'testLocation',
58
+ variationId: 'testVariation'
59
+ }
60
+ }
61
+ };
62
+ const trackingEvent = getTrackingEvent(actionIn);
63
+ expect(keyRegex.test(trackingEvent[0])).toEqual(true);
64
+ expect(trackingEvent[1]).toEqual('testProduct,optout_product,testLocation,,testVariation');
65
+ });
66
+
67
+ it('make tracking event for optin', () => {
68
+ const actionIn = {
69
+ type: 'OPTIN_PRODUCT',
70
+ payload: {
71
+ product: {
72
+ id: 'testProduct'
73
+ },
74
+ offer: {
75
+ location: 'testLocation',
76
+ variationId: 'testVariation'
77
+ },
78
+ frequency: 'testFrequency'
79
+ }
80
+ };
81
+ const trackingEvent = getTrackingEvent(actionIn);
82
+ expect(keyRegex.test(trackingEvent[0])).toEqual(true);
83
+ expect(trackingEvent[1]).toEqual('testProduct,optin_product,testLocation,testFrequency,testVariation');
84
+ });
85
+ });
86
+
46
87
  describe('synchronizeCartOptin', () => {
47
88
  let store, offer, frequency, product;
48
89
  beforeEach(() => {
@@ -0,0 +1,125 @@
1
+ import { updateTrackingInputs, addDefaultToSubTracking } from '../shopifyTrackingMiddleware';
2
+
3
+ function makeForm() {
4
+ const element = document.createElement('form');
5
+ element.action = '/cart/add';
6
+ element.innerHTML = `
7
+ <input value="123456" name="id" type="hidden">
8
+ `;
9
+ document.body.appendChild(element);
10
+ return element;
11
+ }
12
+
13
+ const testProduct = '123456';
14
+
15
+ describe('updateTrackingInputs', () => {
16
+ let formElement;
17
+ beforeEach(() => {
18
+ formElement = makeForm();
19
+ });
20
+
21
+ afterEach(() => {
22
+ formElement.remove();
23
+ });
24
+
25
+ const testName = 'og__123456789';
26
+ const testValue = '123456,optin_product,pdp,yay_selling_plan,yay_variant';
27
+
28
+ it('should add tracking input with all values passed in', () => {
29
+ expect(formElement.querySelector(`[name="attributes[${testName}]"]`)).toBeFalsy();
30
+ updateTrackingInputs(testProduct, testName, testValue);
31
+ const newInput = formElement.querySelector(`[name="attributes[${testName}]"]`);
32
+ expect(newInput).toBeTruthy();
33
+ expect(newInput.getAttribute('value')).toEqual(testValue);
34
+ });
35
+
36
+ it('should not add input if one already exists with the same name', () => {
37
+ updateTrackingInputs(testProduct, testName, testValue);
38
+ const newInput = formElement.querySelectorAll(`[name="attributes[${testName}]"]`);
39
+ expect(newInput.length).toBe(1);
40
+ updateTrackingInputs(testProduct, testName, testValue);
41
+ expect(newInput.length).toBe(1);
42
+ });
43
+
44
+ it('should add inputs to multiple forms if existing', () => {
45
+ const formElement1 = makeForm();
46
+ const formElement2 = makeForm();
47
+ updateTrackingInputs(testProduct, testName, testValue);
48
+ const newInput1 = formElement1.querySelector(`[name="attributes[${testName}]"]`);
49
+ const newInput2 = formElement2.querySelector(`[name="attributes[${testName}]"]`);
50
+ expect(newInput1).toBeTruthy();
51
+ expect(newInput2).toBeTruthy();
52
+ expect(newInput1).toEqual(newInput2);
53
+ formElement1.remove();
54
+ formElement2.remove();
55
+ });
56
+ });
57
+
58
+ describe('addDefaultToSubTracking', () => {
59
+ const keyRegex = new RegExp('attributes[og__[0-9]+]');
60
+
61
+ const defaultValue = `${testProduct},optin_product,testLocation,4_2,testVariation`;
62
+ const inputSelector = `[value="${defaultValue}"]`;
63
+
64
+ const storeOg = {
65
+ getState: () => {
66
+ return { optedin: [{ id: testProduct, frequency: '4_2' }] };
67
+ }
68
+ };
69
+
70
+ let formElement;
71
+ beforeEach(() => {
72
+ formElement = makeForm();
73
+ });
74
+
75
+ afterEach(() => {
76
+ formElement.remove();
77
+ });
78
+
79
+ it('make tracking event for default to sub optin for RECEIVE_OFFER', () => {
80
+ const actionReceiveOffer = {
81
+ type: 'RECEIVE_OFFER',
82
+ payload: {
83
+ product: {
84
+ id: testProduct
85
+ },
86
+ offer: {
87
+ location: 'testLocation',
88
+ variationId: 'testVariation',
89
+ autoshipByDefault: true,
90
+ product: {
91
+ id: testProduct
92
+ }
93
+ }
94
+ }
95
+ };
96
+ expect(document.querySelector(inputSelector)).toBeFalsy();
97
+ addDefaultToSubTracking(actionReceiveOffer, storeOg);
98
+ const defaultInput = document.querySelector(inputSelector);
99
+ expect(defaultInput).toBeTruthy();
100
+ expect(keyRegex.test(defaultInput.name)).toEqual(true);
101
+ expect(defaultInput.value).toEqual(defaultValue);
102
+ });
103
+
104
+ it('should not make input if product is not default-to-sub', () => {
105
+ const actionReceiveOffer = {
106
+ type: 'RECEIVE_OFFER',
107
+ payload: {
108
+ product: {
109
+ id: testProduct
110
+ },
111
+ offer: {
112
+ location: 'testLocation',
113
+ variationId: 'testVariation',
114
+ product: {
115
+ id: testProduct
116
+ }
117
+ }
118
+ }
119
+ };
120
+ expect(document.querySelector(inputSelector)).toBeFalsy();
121
+ addDefaultToSubTracking(actionReceiveOffer, storeOg);
122
+ const defaultInput = document.querySelector(inputSelector);
123
+ expect(defaultInput).toBeFalsy();
124
+ });
125
+ });
@@ -14,6 +14,7 @@ import {
14
14
 
15
15
  import { makeSubscribedSelector } from '../core/selectors';
16
16
  import { getOrCreateHidden, safeProductId } from '../core/utils';
17
+ import { getTrackingKey } from './shopifyTrackingMiddleware';
17
18
 
18
19
  const SHOPIFY_ROOT = window.Shopify?.routes?.root || '/';
19
20
  const CART_PAGE_URL = '/cart';
@@ -262,7 +263,7 @@ export async function synchronizeCartOptin(action: any, store: any) {
262
263
  export function getTrackingEvent(action): Array<string> {
263
264
  const product_id = action.payload.product.id;
264
265
  if (!product_id) return [];
265
- const key = `og__${Math.ceil(new Date().getTime() / 1000)}`;
266
+ const key = getTrackingKey();
266
267
  const location = action.payload.offer?.location || '';
267
268
  const variation = action.payload.offer?.variationId || '';
268
269
  const value = [product_id, action.type.toLowerCase(), location];
@@ -285,6 +286,12 @@ export function getTrackingEvent(action): Array<string> {
285
286
  return [key, value.join(',')];
286
287
  }
287
288
 
289
+ export function getSubscribedFrequency(productId, store) {
290
+ const subscribedSelector = makeSubscribedSelector({ id: productId });
291
+ const sellingPlanId = subscribedSelector(store.getState())?.frequency;
292
+ return sellingPlanId;
293
+ }
294
+
288
295
  /**
289
296
  * // update <input type="hidden" name="selling_plan"/> if available
290
297
  *
@@ -296,8 +303,7 @@ function synchronizeSellingPlan(store: any, offerElement?: HTMLElement) {
296
303
  [...document.querySelectorAll('form[action$="/cart/add"] [name=id]')].forEach((productIdInput: HTMLInputElement) => {
297
304
  const productId = productIdInput.value;
298
305
 
299
- const subscribedSelector = makeSubscribedSelector({ id: productId });
300
- const sellingPlanId = subscribedSelector(store.getState())?.frequency;
306
+ const sellingPlanId = getSubscribedFrequency(productId, store);
301
307
 
302
308
  getOrCreateHidden(productIdInput.form, 'selling_plan', sellingPlanId);
303
309
  if (offerElement) {
@@ -1,5 +1,5 @@
1
- import { OPTIN_PRODUCT, OPTOUT_PRODUCT, PRODUCT_CHANGE_FREQUENCY } from '../core/constants';
2
- import { getTrackingEvent } from './shopifyMiddleware';
1
+ import { OPTIN_PRODUCT, OPTOUT_PRODUCT, PRODUCT_CHANGE_FREQUENCY, RECEIVE_OFFER, SETUP_PRODUCT } from '../core/constants';
2
+ import { getTrackingEvent, getSubscribedFrequency } from './shopifyMiddleware';
3
3
 
4
4
  /**
5
5
  * Creates or updates a hidden input used for tracking on non-cart pages
@@ -31,6 +31,27 @@ export function updateTrackingInputs(product_id: string, name: string, value: st
31
31
  });
32
32
  }
33
33
 
34
+ export function getTrackingKey() {
35
+ return `og__${Math.ceil(new Date().getTime() / 1000)}`;
36
+ }
37
+
38
+ export function addDefaultToSubTracking(action, store) {
39
+ // check if default to sub
40
+ const isDefaultToSub = action.payload.offer?.autoshipByDefault;
41
+ if (!isDefaultToSub) return;
42
+
43
+ // if default to sub, get tracking info
44
+ const productId = action.payload.offer?.product.id;
45
+ const key = getTrackingKey();
46
+ const location = action.payload.offer?.location || '';
47
+ const variation = action.payload.offer?.variationId || '';
48
+ const frequency = getSubscribedFrequency(productId, store);
49
+ const value = [productId, OPTIN_PRODUCT.toLowerCase(), location, frequency, variation];
50
+ const inputValue = value.join(',');
51
+ updateTrackingInputs(productId, key, inputValue);
52
+
53
+ }
54
+
34
55
  export default function shopifyTrackingMiddleware(store) {
35
56
  return next => action => {
36
57
  next(action);
@@ -46,6 +67,9 @@ export default function shopifyTrackingMiddleware(store) {
46
67
  updateTrackingInputs(offerElement.product.id, trackingEvent[0], trackingEvent[1]);
47
68
  }
48
69
  break;
70
+ case RECEIVE_OFFER:
71
+ addDefaultToSubTracking(action, store);
72
+ break;
49
73
  default:
50
74
  }
51
75
  };