@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.
Files changed (58) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +34 -0
  3. package/build.js +3 -1
  4. package/dist/bundle-report.html +186 -117
  5. package/dist/examples.js +18 -3
  6. package/dist/examples.js.map +1 -1
  7. package/dist/offers.js +65 -76
  8. package/dist/offers.js.map +3 -3
  9. package/examples/cart.js +105 -0
  10. package/examples/index.html +2 -2
  11. package/examples/products/cheap-watch.js +183 -0
  12. package/examples/shopify-cart.html +26 -0
  13. package/examples/shopify-pdp.html +34 -0
  14. package/karma.conf.js +2 -1
  15. package/package.json +5 -5
  16. package/src/__tests__/offers.spec.js +35 -10
  17. package/src/components/FrequencyStatus.js +14 -11
  18. package/src/components/IncentiveText.js +2 -1
  19. package/src/components/Offer.js +14 -7
  20. package/src/components/OptinButton.js +1 -1
  21. package/src/components/OptinSelect.js +2 -2
  22. package/src/components/OptinToggle.js +2 -2
  23. package/src/components/OptoutButton.js +1 -1
  24. package/src/components/Price.js +8 -4
  25. package/src/components/Select.js +3 -13
  26. package/src/components/SelectFrequency.js +24 -6
  27. package/src/components/TestWizard.js +1 -1
  28. package/src/components/__tests__/OG.fspec.js +24 -0
  29. package/src/components/__tests__/Offer.spec.js +4 -4
  30. package/src/components/__tests__/OptinButton.spec.js +2 -2
  31. package/src/components/__tests__/OptinToggle.spec.js +2 -2
  32. package/src/components/__tests__/OptoutButton.spec.js +1 -1
  33. package/src/components/__tests__/SelectFrequency.fspec.js +1 -0
  34. package/src/components/__tests__/SelectFrequency.spec.js +1 -1
  35. package/src/components/__tests__/TestWizard.spec.js +2 -2
  36. package/src/components/__tests__/Text.spec.js +5 -1
  37. package/src/core/__tests__/actions.spec.js +6 -6
  38. package/src/core/actions.js +22 -17
  39. package/src/core/constants.js +21 -0
  40. package/src/core/descriptors.js +2 -1
  41. package/src/core/middleware.js +41 -1
  42. package/src/core/reducer.js +22 -21
  43. package/src/core/resolveProperties.js +2 -7
  44. package/src/core/selectors.js +1 -1
  45. package/src/core/store.js +17 -9
  46. package/src/core/utils.ts +67 -0
  47. package/src/index.js +46 -203
  48. package/src/make-api.js +195 -0
  49. package/src/platform.ts +9 -0
  50. package/src/shopify/__tests__/shopifyMiddleware.spec.js +126 -0
  51. package/src/shopify/__tests__/shopifyReducer.spec.js +489 -0
  52. package/src/shopify/shopifyBootstrap.ts +136 -0
  53. package/src/shopify/shopifyMiddleware.ts +336 -0
  54. package/src/shopify/shopifyReducer.js +254 -0
  55. package/tsconfig.json +35 -0
  56. package/examples/5starnutrition-main.js +0 -3
  57. package/examples/single-offer.html +0 -9
  58. package/src/init-test.js +0 -3
@@ -0,0 +1,105 @@
1
+ {
2
+ "################################# README ":"This file is for Dev only and meant to match shopify /cart.js api. Should be json but with js extension",
3
+ "note": null,
4
+ "attributes": {},
5
+ "original_total_price": 2670,
6
+ "total_price": 2670,
7
+ "total_discount": 0,
8
+ "total_weight": 0.0,
9
+ "item_count": 3,
10
+ "items": [
11
+ {
12
+ "id": 40909392609469,
13
+ "properties": {
14
+ "_og-cart-interactions": [
15
+ "frequency change",
16
+ "frequency change",
17
+ "frequency change",
18
+ "frequency change",
19
+ "frequency change",
20
+ "frequency change"
21
+ ]
22
+ },
23
+ "quantity": 3,
24
+ "variant_id": 40909392609469,
25
+ "key": "40909392609469:e0e784cd9cab078d741e3fb4a5f35a94",
26
+ "title": "Cheap Watch",
27
+ "price": 890,
28
+ "original_price": 890,
29
+ "discounted_price": 890,
30
+ "line_price": 2670,
31
+ "original_line_price": 2670,
32
+ "total_discount": 0,
33
+ "discounts": [],
34
+ "sku": "",
35
+ "grams": 0,
36
+ "vendor": "Clara's Clocks",
37
+ "taxable": true,
38
+ "product_id": 7032252694717,
39
+ "product_has_only_default_variant": true,
40
+ "gift_card": false,
41
+ "final_price": 890,
42
+ "final_line_price": 2670,
43
+ "url": "\/products\/cheap-watch?variant=40909392609469",
44
+ "featured_image": {
45
+ "aspect_ratio": 0.728,
46
+ "alt": "Cheap Watch",
47
+ "height": 717,
48
+ "url": "https:\/\/cdn.shopify.com\/s\/files\/1\/0596\/3526\/9821\/products\/71unaYjYidL._AC_UX522.jpg?v=1634657932",
49
+ "width": 522
50
+ },
51
+ "image": "https:\/\/cdn.shopify.com\/s\/files\/1\/0596\/3526\/9821\/products\/71unaYjYidL._AC_UX522.jpg?v=1634657932",
52
+ "handle": "cheap-watch",
53
+ "requires_shipping": true,
54
+ "product_type": "",
55
+ "product_title": "Cheap Watch",
56
+ "product_description": "A cheap rainbow watch.",
57
+ "variant_title": null,
58
+ "variant_options": ["Default Title"],
59
+ "options_with_values": [
60
+ {
61
+ "name": "Title",
62
+ "value": "Default Title"
63
+ }
64
+ ],
65
+ "line_level_discount_allocations": [],
66
+ "line_level_total_discount": 0,
67
+ "selling_plan_allocation": {
68
+ "price_adjustments": [
69
+ {
70
+ "position": 1,
71
+ "price": 890
72
+ }
73
+ ],
74
+ "price": 890,
75
+ "compare_at_price": 1000,
76
+ "per_delivery_price": 890,
77
+ "selling_plan": {
78
+ "id": 547455165,
79
+ "name": "Delivered every 3 months, get 11% off your first order",
80
+ "description": null,
81
+ "options": [
82
+ {
83
+ "name": "Delivery every",
84
+ "position": 1,
85
+ "value": "3 months"
86
+ }
87
+ ],
88
+ "recurring_deliveries": true,
89
+ "price_adjustments": [
90
+ {
91
+ "order_count": null,
92
+ "position": 1,
93
+ "value_type": "percentage",
94
+ "value": 11
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ }
100
+ ],
101
+ "requires_shipping": true,
102
+ "currency": "USD",
103
+ "items_subtotal_price": 2670,
104
+ "cart_level_discount_applications": []
105
+ }
@@ -121,8 +121,8 @@
121
121
 
122
122
  <pre id="the-html"></pre>
123
123
  <textarea id="the-js" readonly></textarea>
124
- <script type="text/javascript" src="examples.js"></script>
124
+ <script type="text/javascript" src="../dist/examples.js"></script>
125
125
  <!-- offers should be latest since it overides og.offers namespace -->
126
- <script type="text/javascript" src="offers.js"></script>
126
+ <script type="text/javascript" src="../dist/offers.js"></script>
127
127
  </body>
128
128
  </html>
@@ -0,0 +1,183 @@
1
+ {
2
+ "################################# README ":"This file is for Dev only and meant to match shopify /products/<handle>.js api. Should be json but with js extension",
3
+ "id": 7032252694717,
4
+ "title": "Cheap Watch",
5
+ "handle": "cheap-watch",
6
+ "description": "A cheap rainbow watch.",
7
+ "published_at": "2021-10-19T11:38:52-04:00",
8
+ "created_at": "2021-10-19T11:38:51-04:00",
9
+ "vendor": "Clara's Clocks",
10
+ "type": "",
11
+ "tags": [],
12
+ "price": 1000,
13
+ "price_min": 1000,
14
+ "price_max": 1000,
15
+ "available": true,
16
+ "price_varies": false,
17
+ "compare_at_price": null,
18
+ "compare_at_price_min": 0,
19
+ "compare_at_price_max": 0,
20
+ "compare_at_price_varies": false,
21
+ "variants": [
22
+ {
23
+ "id": 40909392609469,
24
+ "title": "Default Title",
25
+ "option1": "Default Title",
26
+ "option2": null,
27
+ "option3": null,
28
+ "sku": "",
29
+ "requires_shipping": true,
30
+ "taxable": true,
31
+ "featured_image": null,
32
+ "available": true,
33
+ "name": "Cheap Watch",
34
+ "public_title": null,
35
+ "options": ["Default Title"],
36
+ "price": 1000,
37
+ "weight": 0,
38
+ "compare_at_price": null,
39
+ "inventory_management": null,
40
+ "barcode": "",
41
+ "requires_selling_plan": true,
42
+ "selling_plan_allocations": [
43
+ {
44
+ "price_adjustments": [
45
+ {
46
+ "position": 1,
47
+ "price": 890
48
+ }
49
+ ],
50
+ "price": 890,
51
+ "compare_at_price": 1000,
52
+ "per_delivery_price": 890,
53
+ "selling_plan_id": 547389629,
54
+ "selling_plan_group_id": "1a1dc6d22dd730c6851c3596f5c46e26ff776cc2"
55
+ }, {
56
+ "price_adjustments": [
57
+ {
58
+ "position": 1,
59
+ "price": 890
60
+ }
61
+ ],
62
+ "price": 890,
63
+ "compare_at_price": 1000,
64
+ "per_delivery_price": 890,
65
+ "selling_plan_id": 547422397,
66
+ "selling_plan_group_id": "1a1dc6d22dd730c6851c3596f5c46e26ff776cc2"
67
+ }, {
68
+ "price_adjustments": [
69
+ {
70
+ "position": 1,
71
+ "price": 890
72
+ }
73
+ ],
74
+ "price": 890,
75
+ "compare_at_price": 1000,
76
+ "per_delivery_price": 890,
77
+ "selling_plan_id": 547455165,
78
+ "selling_plan_group_id": "1a1dc6d22dd730c6851c3596f5c46e26ff776cc2"
79
+ }
80
+ ]
81
+ }
82
+ ],
83
+ "images": ["//cdn.shopify.com/s/files/1/0596/3526/9821/products/71unaYjYidL._AC_UX522.jpg?v=1634657932"],
84
+ "featured_image": "//cdn.shopify.com/s/files/1/0596/3526/9821/products/71unaYjYidL._AC_UX522.jpg?v=1634657932",
85
+ "options": ["Title"],
86
+ "media": [
87
+ {
88
+ "alt": null,
89
+ "id": 22999019061437,
90
+ "position": 1,
91
+ "preview_image": {
92
+ "aspect_ratio": 0.728,
93
+ "height": 717,
94
+ "width": 522,
95
+ "src": "https://cdn.shopify.com/s/files/1/0596/3526/9821/products/71unaYjYidL._AC_UX522.jpg?v=1634657932"
96
+ },
97
+ "aspect_ratio": 0.728,
98
+ "height": 717,
99
+ "media_type": "image",
100
+ "src": "https://cdn.shopify.com/s/files/1/0596/3526/9821/products/71unaYjYidL._AC_UX522.jpg?v=1634657932",
101
+ "width": 522
102
+ }
103
+ ],
104
+ "requires_selling_plan": true,
105
+ "selling_plan_groups": [
106
+ {
107
+ "id": "1a1dc6d22dd730c6851c3596f5c46e26ff776cc2",
108
+ "name": "Subscribe and Save",
109
+ "options": [
110
+ {
111
+ "name": "Delivery every",
112
+ "position": 1,
113
+ "values": ["month", "2 months", "3 months"]
114
+ }
115
+ ],
116
+ "selling_plans": [
117
+ {
118
+ "id": 547389629,
119
+ "name": "Delivered every month, get 11% off your first order",
120
+ "description": null,
121
+ "options": [
122
+ {
123
+ "name": "Delivery every",
124
+ "position": 1,
125
+ "value": "month"
126
+ }
127
+ ],
128
+ "recurring_deliveries": true,
129
+ "price_adjustments": [
130
+ {
131
+ "order_count": null,
132
+ "position": 1,
133
+ "value_type": "percentage",
134
+ "value": 11
135
+ }
136
+ ]
137
+ }, {
138
+ "id": 547422397,
139
+ "name": "Delivered every 2 months, get 11% off your first order",
140
+ "description": null,
141
+ "options": [
142
+ {
143
+ "name": "Delivery every",
144
+ "position": 1,
145
+ "value": "2 months"
146
+ }
147
+ ],
148
+ "recurring_deliveries": true,
149
+ "price_adjustments": [
150
+ {
151
+ "order_count": null,
152
+ "position": 1,
153
+ "value_type": "percentage",
154
+ "value": 11
155
+ }
156
+ ]
157
+ }, {
158
+ "id": 547455165,
159
+ "name": "Delivered every 3 months, get 11% off your first order",
160
+ "description": null,
161
+ "options": [
162
+ {
163
+ "name": "Delivery every",
164
+ "position": 1,
165
+ "value": "3 months"
166
+ }
167
+ ],
168
+ "recurring_deliveries": true,
169
+ "price_adjustments": [
170
+ {
171
+ "order_count": null,
172
+ "position": 1,
173
+ "value_type": "percentage",
174
+ "value": 11
175
+ }
176
+ ]
177
+ }
178
+ ],
179
+ "app_id": null
180
+ }
181
+ ],
182
+ "content": "A cheap rainbow watch."
183
+ }
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Ordergroove Offers</title>
5
+ </head>
6
+ <body id="single-offer" >
7
+ <h1>cart</h1>
8
+ <og-offer product="40909392609469" id="regular1" location="cart" cart></og-offer>
9
+ <!-- offers should be latest since it overides og.offers namespace -->
10
+
11
+ <script type="text/javascript">
12
+ var Shopify = {
13
+ routes: {
14
+ root: './'
15
+ }
16
+ }
17
+ </script>
18
+ <script type="text/javascript" src="../dist/offers.js"></script>
19
+ <script type="text/javascript">
20
+ og
21
+ .offers
22
+ .initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging')
23
+ </script>
24
+
25
+ </body>
26
+ </html>
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Ordergroove Offers</title>
5
+
6
+ <meta property="og:type" content="product">
7
+ <meta property="og:url" content="https://claras-clocks.myshopify.com/products/cheap-watch">
8
+
9
+ </head>
10
+ <body id="single-offer" >
11
+
12
+ <form action="shopify-cart.html" menthod="POST">
13
+ <og-offer product="40909392609469" id="regular1"></og-offer>
14
+ <!-- offers should be latest since it overides og.offers namespace -->
15
+ <button> Add to cart</button>
16
+ </form>
17
+
18
+ <script type="text/javascript">
19
+ var Shopify = {
20
+ routes: {
21
+ root: './'
22
+ }
23
+ }
24
+ </script>
25
+
26
+ <script type="text/javascript" src="../dist/offers.js"></script>
27
+
28
+ <script type="text/javascript">
29
+ og
30
+ .offers
31
+ .initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging')
32
+ </script>
33
+ </body>
34
+ </html>
package/karma.conf.js CHANGED
@@ -9,8 +9,9 @@ module.exports = function(config) {
9
9
 
10
10
  // list of files / patterns to load in the browser
11
11
  files: [
12
+ // make sure is the first on the list that inits the offers module
12
13
  {
13
- pattern: 'src/init-test.js',
14
+ pattern: 'src/__tests__/offers.spec.js',
14
15
  type: 'js',
15
16
  included: true,
16
17
  served: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/offers",
3
- "version": "2.26.9",
3
+ "version": "2.27.0",
4
4
  "description": "offer state component",
5
5
  "author": "Eugenio Lattanzio <eugenio63@gmail.com>",
6
6
  "homepage": "https://github.com/ordergroove/plush-toys#readme",
@@ -12,14 +12,14 @@
12
12
  },
13
13
  "scripts": {
14
14
  "start": "npm run build -- --serve",
15
- "build": "rm -rf dist && mkdir dist && cp examples/index.html dist/index.html && node build.js",
15
+ "build": "rm -rf dist && mkdir dist && node build.js",
16
16
  "build:prod": "rm -rf dist && node build.js --prod",
17
17
  "bundlesize": "../../node_modules/.bin/bundlesize",
18
18
  "lint": "../../node_modules/.bin/eslint --ignore-path ../../.gitignore ./src",
19
19
  "prepublishOnly": "npm run -s build:prod && npm run -s bundlesize",
20
20
  "test": "../../node_modules/.bin/karma start --single-run --log-level error --reporters progress && npm run build && ../../node_modules/.bin/karma start --single-run --log-level error --reporters progress karma-functional.conf.js",
21
21
  "test:watch": "../../node_modules/.bin/karma start",
22
- "test:watch:functional": "npm run build:dev && ../../node_modules/.bin/karma start karma-functional.conf.js",
22
+ "test:watch:functional": "npm run build && ../../node_modules/.bin/karma start karma-functional.conf.js",
23
23
  "test:functional": "npm run test:watch:functional -- --single-run --log-level error --reporters progress",
24
24
  "test:watch:silent": "../../node_modules/.bin/karma start --log-level error --reporters dots"
25
25
  },
@@ -43,7 +43,7 @@
43
43
  "throttle-debounce": "^2.1.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@ordergroove/offers-templates": "^0.4.10"
46
+ "@ordergroove/offers-templates": "^0.4.12"
47
47
  },
48
- "gitHead": "adcabf7f77d65b67f7d6ea08315acb37de44032e"
48
+ "gitHead": "5494ac90e797dee202a99a40a81a191061a1d042"
49
49
  }
@@ -1,6 +1,36 @@
1
- import { offers } from '../index';
1
+ import * as offersAll from '../index';
2
2
  import { api } from '../core/api';
3
3
 
4
+ const offers = offersAll.offers;
5
+
6
+ describe('Offers API', () => {
7
+ // offers.initialize('some-merchant', 'staging');
8
+ const facade = jasmine.objectContaining({
9
+ store: jasmine.any(Object),
10
+ addOptinChangedCallback: jasmine.any(Function),
11
+ addTemplate: jasmine.any(Function),
12
+ clear: jasmine.any(Function),
13
+ config: jasmine.any(Function),
14
+ disableOptinChangedCallbacks: jasmine.any(Function),
15
+ getOptins: jasmine.any(Function),
16
+ getProductsForPurchasePost: jasmine.any(Function),
17
+ initialize: jasmine.any(Function),
18
+ previewMode: jasmine.any(Function),
19
+ register: jasmine.any(Function),
20
+ resolveSettings: jasmine.any(Function),
21
+ setAuthUrl: jasmine.any(Function),
22
+ setEnvironment: jasmine.any(Function),
23
+ setLocale: jasmine.any(Function),
24
+ setMerchantId: jasmine.any(Function),
25
+ setPublicPath: jasmine.any(Function),
26
+ setTemplates: jasmine.any(Function)
27
+ });
28
+ it('imported ', () => {
29
+ expect(offersAll).toEqual(facade);
30
+ expect(offers).toEqual(facade);
31
+ });
32
+ });
33
+
4
34
  describe('Offers', () => {
5
35
  let register, fetchOfferSpy, mockStore;
6
36
  // TODO revisit chunks
@@ -23,25 +53,20 @@ describe('Offers', () => {
23
53
  });
24
54
 
25
55
  it('should warn if attempting to initialize twice', () => {
56
+ const resolveSettings = spyOn(offers, 'resolveSettings');
26
57
  const warn = spyOn(console, 'warn');
27
58
 
28
59
  offers.initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging');
29
60
  expect(warn).not.toHaveBeenCalled();
30
-
31
- offers.initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging');
32
- expect(warn).toHaveBeenCalledWith('og.offers has been initialized already. Skipping.');
33
- expect(register).toHaveBeenCalledTimes(1);
34
- });
35
-
36
- it('should warn if attempting to initialize twice', () => {
37
- const resolveSettings = spyOn(offers, 'resolveSettings');
38
- offers.initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging');
39
61
  expect(resolveSettings).toHaveBeenCalledWith(
40
62
  '0e5de2bedc5e11e3a2e4bc764e106cf4',
41
63
  'staging',
42
64
  undefined,
43
65
  offers.store
44
66
  );
67
+ offers.initialize('0e5de2bedc5e11e3a2e4bc764e106cf4', 'staging');
68
+ expect(warn).toHaveBeenCalledWith('og.offers has been initialized already. Skipping.');
69
+ expect(register).not.toHaveBeenCalled();
45
70
  });
46
71
 
47
72
  describe('offers.resolveSettings', () => {
@@ -14,16 +14,17 @@ import { TemplateElement } from '../core/base';
14
14
 
15
15
  export const frequencyText = (frequency, initial) => {
16
16
  const { every, every_period: period } = parseFrequency(frequency);
17
-
18
- return html`
19
- ${every}
20
- <og-text key="frequencyPeriods" variant="${period}" pluralize="${every}"></og-text>
21
- ${initial && initial === frequency
22
- ? html`
23
- <og-text key="defaultFrequencyCopy"></og-text>
24
- `
25
- : ''}
26
- `;
17
+ return every && period
18
+ ? html`
19
+ ${every}
20
+ <og-text key="frequencyPeriods" variant="${period}" pluralize="${every}"></og-text>
21
+ ${initial && initial === frequency
22
+ ? html`
23
+ <og-text key="defaultFrequencyCopy"></og-text>
24
+ `
25
+ : ''}
26
+ `
27
+ : frequency;
27
28
  };
28
29
 
29
30
  export class FrequencyStatus extends withProduct(TemplateElement) {
@@ -90,7 +91,9 @@ export const mapStateToProps = (state, ownProps) => ({
90
91
  subscribed: makeOptedinSelector(ownProps.product)(state),
91
92
  frequency: makeProductFrequencySelector(ownProps.product)(state),
92
93
  productDefaultFrequency: makeProductDefaultFrequencySelector((ownProps.product || {}).id)(state),
93
- ...configSelector(state, ownProps, 'frequencies', []),
94
+ configDefaultFrequency: state.config?.defaultFrequency,
95
+ frequenciesText: state.config?.frequenciesText,
96
+ ...configSelector(state, ownProps, 'frequencies'),
94
97
  ...configSelector(state, ownProps, 'defaultFrequency'),
95
98
  ...templatesSelector(state, ownProps)
96
99
  });
@@ -1,6 +1,7 @@
1
1
  import { LitElement, html } from 'lit-element';
2
2
  import { connect } from '../core/connect';
3
3
  import { withProduct } from '../core/resolveProperties';
4
+ import { safeProductId } from '../core/utils';
4
5
 
5
6
  export class DiscountAmount {
6
7
  constructor(value) {
@@ -121,7 +122,7 @@ export class IncentiveText extends withProduct(LitElement) {
121
122
  }
122
123
 
123
124
  export const mapStateToProps = (state, ownProps) => ({
124
- incentives: (state.incentives || {})[ownProps && ownProps.product && ownProps.product.id] || {}
125
+ incentives: (state.incentives || {})[ownProps && ownProps?.product && safeProductId(ownProps?.product?.id)] || {}
125
126
  });
126
127
 
127
128
  export const ConnectedIncentiveText = connect(mapStateToProps)(IncentiveText);
@@ -23,6 +23,8 @@ import {
23
23
  } from '../core/selectors';
24
24
  import { product as productProp, auth as authProp } from '../core/props';
25
25
  import { TemplateElement } from '../core/base';
26
+ import { onReady } from '../core/utils';
27
+ import { DEFAULT_OFFER_MODULE } from '../core/constants';
26
28
 
27
29
  const memoizeKey = (...args) => JSON.stringify(args);
28
30
 
@@ -49,7 +51,10 @@ export class Offer extends TemplateElement {
49
51
  firstOrderPlaceDate: { type: String, attribute: 'first-order-place-date' },
50
52
  productToSubscribe: { type: String, attribute: 'product-to-subscribe' },
51
53
  subscribed: { type: Boolean, reflect: true },
52
- frequency: { type: String, reflect: true }
54
+ frequency: { type: String, reflect: true },
55
+ productFrequency: { type: String },
56
+ isCart: { type: Boolean, attribute: 'cart' },
57
+ optedin: { type: Object }
53
58
  };
54
59
  }
55
60
 
@@ -141,11 +146,10 @@ export class Offer extends TemplateElement {
141
146
  </div>
142
147
  <div>
143
148
  <og-optin-button>
144
-
145
-
146
149
  <og-price discount>
147
150
  <span slot="prepend">Subscribe and get</span>
148
151
  <span slot="append">off</span>
152
+ <og-text key="offerOptInLabel" slot="fallback"></og-text>
149
153
  </og-price>
150
154
  <og-price regular></og-price>
151
155
  <og-price subscription></og-price>
@@ -213,6 +217,7 @@ export class Offer extends TemplateElement {
213
217
  The product is in your next upcomming order
214
218
  </og-when>
215
219
  </og-when>
220
+
216
221
  `;
217
222
  }
218
223
 
@@ -241,10 +246,10 @@ export class Offer extends TemplateElement {
241
246
  if (changed.has('preview')) {
242
247
  this.setPreview(this.preview, changed.get('preview'), this);
243
248
  }
244
-
245
249
  this.frequency = this.defaultFrequency;
250
+
246
251
  if (changed.has('product') && this.product.id && !this.isPreview) {
247
- this.fetchOffer(this.product.id);
252
+ onReady(() => this.fetchOffer(this.product.id, DEFAULT_OFFER_MODULE, this));
248
253
  }
249
254
 
250
255
  if (changed.has('firstOrderPlaceDate') && this.product.id && !this.isPreview) {
@@ -277,7 +282,7 @@ export class Offer extends TemplateElement {
277
282
  changed.has('product')) &&
278
283
  this.offerId &&
279
284
  this.autoshipByDefault &&
280
- this.location === 'cart' &&
285
+ (this.location === 'cart' || this.isCart) &&
281
286
  this.product.id &&
282
287
  this.optinProduct &&
283
288
  !(this.optedin || []).find(product => isSameProduct(product, this.product))
@@ -287,7 +292,8 @@ export class Offer extends TemplateElement {
287
292
  ...this.product,
288
293
  ...(this.productComponents.length && { components: this.productComponents })
289
294
  },
290
- this.defaultFrequency
295
+ this.defaultFrequency,
296
+ this
291
297
  );
292
298
  }
293
299
  }
@@ -329,6 +335,7 @@ export const mapStateToProps = (state, ownProps) => ({
329
335
  subscribed: makeOptedinSelector(ownProps.product)(state),
330
336
  ...templatesSelector(state)
331
337
  });
338
+
332
339
  export const ConnectedOffer = connect(mapStateToProps, {
333
340
  fetchOffer,
334
341
  fetchOrders,
@@ -16,7 +16,7 @@ export class OptinButton extends OptinStatus {
16
16
  }
17
17
 
18
18
  handleClick(ev) {
19
- this.optinProduct(resolveProduct(this), this.defaultFrequency);
19
+ this.optinProduct(resolveProduct(this), this.defaultFrequency, this.offer);
20
20
  ev.preventDefault();
21
21
  }
22
22
 
@@ -36,9 +36,9 @@ export class OptinSelect extends withChildOptions(OptinStatus) {
36
36
 
37
37
  onOptinChange(value) {
38
38
  if (value === 'optedOut') {
39
- this.optoutProduct(this.product);
39
+ this.optoutProduct(this.product, this.offer);
40
40
  } else {
41
- this.productChangeFrequency(this.product, value);
41
+ this.productChangeFrequency(this.product, value, this.offer);
42
42
  }
43
43
  }
44
44
 
@@ -49,8 +49,8 @@ export class OptinToggle extends OptinStatus {
49
49
  }
50
50
 
51
51
  handleClick(ev) {
52
- if (this.subscribed) this.optoutProduct(this.product);
53
- else this.optinProduct(this.product, this.frequency || this.defaultFrequency);
52
+ if (this.subscribed) this.optoutProduct(this.product, this.offer);
53
+ else this.optinProduct(this.product, this.frequency || this.defaultFrequency, this.offer);
54
54
  ev.preventDefault();
55
55
  }
56
56
 
@@ -12,7 +12,7 @@ export class OptoutButton extends OptinStatus {
12
12
  }
13
13
 
14
14
  handleClick(ev) {
15
- this.optoutProduct(this.product);
15
+ this.optoutProduct(this.product, this.offer);
16
16
  ev.preventDefault();
17
17
  }
18
18