@ordergroove/offers 2.36.1 → 2.36.2-alpha-PR-836-4.4
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/dist/bundle-report.html +7 -7
- package/dist/offers.js +28 -28
- package/dist/offers.js.map +3 -3
- package/package.json +2 -2
- package/src/components/Offer.js +25 -11
- package/src/components/SelectFrequency.js +4 -5
- package/src/components/__tests__/Offer.spec.js +37 -18
- package/src/core/__tests__/utils.spec.js +9 -1
- package/src/core/utils.ts +6 -0
- package/src/shopify/__tests__/shopifyReducer.spec.js +94 -13
- package/src/shopify/shopifyReducer.js +14 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/offers",
|
|
3
|
-
"version": "2.36.
|
|
3
|
+
"version": "2.36.2-alpha-PR-836-4.4+979e5e4f",
|
|
4
4
|
"description": "offer state component",
|
|
5
5
|
"author": "Eugenio Lattanzio <eugenio63@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/ordergroove/plush-toys#readme",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"@ordergroove/offers-templates": "^0.9.6",
|
|
49
49
|
"@types/lodash.memoize": "^4.1.9"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "979e5e4f88661c37d410fc44a0a8c658938a23d9"
|
|
52
52
|
}
|
package/src/components/Offer.js
CHANGED
|
@@ -28,16 +28,24 @@ import { DEFAULT_OFFER_MODULE } from '../core/constants';
|
|
|
28
28
|
|
|
29
29
|
const memoizeKey = (...args) => JSON.stringify(args);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
const logOnce = messageFn => {
|
|
32
|
+
let hasLogged = false;
|
|
33
|
+
return (...args) => {
|
|
34
|
+
if (!hasLogged) {
|
|
35
|
+
console.warn(messageFn(...args));
|
|
36
|
+
hasLogged = true;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const logMulticurrencyWarning = logOnce(
|
|
42
|
+
(storeCurrency, primaryCurrency) =>
|
|
43
|
+
`Hiding Ordergroove offer since the store currency ${storeCurrency} does not match your configured currency ${primaryCurrency} and you are not set up for multicurrency. Contact your Ordergroove representative for next steps.`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const logProductSpecificFrequencyListWarning = logOnce(
|
|
47
|
+
() => `Hiding Ordergroove offer since cart offers does not currently support product-specific frequency lists.`
|
|
48
|
+
);
|
|
41
49
|
|
|
42
50
|
export const productAndComponents = memoize(
|
|
43
51
|
(product, components) => Object.assign({ components }, product),
|
|
@@ -327,8 +335,14 @@ export class Offer extends TemplateElement {
|
|
|
327
335
|
this.config.storeCurrency === this.config.merchantSettings.currency_code;
|
|
328
336
|
if (!shouldEnable) {
|
|
329
337
|
logMulticurrencyWarning(this.config.storeCurrency, this.config.merchantSettings.currency_code);
|
|
338
|
+
return false;
|
|
330
339
|
}
|
|
331
|
-
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// product-specific frequency lists are not supported in cart offers
|
|
343
|
+
if (this.isCart && this.config?.hasProductSpecificFrequencies) {
|
|
344
|
+
logProductSpecificFrequencyListWarning();
|
|
345
|
+
return false;
|
|
332
346
|
}
|
|
333
347
|
|
|
334
348
|
return true;
|
|
@@ -3,6 +3,7 @@ import { productChangeFrequency } from '../core/actions';
|
|
|
3
3
|
import { withChildOptions } from '../core/resolveProperties';
|
|
4
4
|
import { FrequencyStatus, mapStateToProps, frequencyText } from './FrequencyStatus';
|
|
5
5
|
import { connect } from '../core/connect';
|
|
6
|
+
import { frequencyToSellingPlan } from '../core/utils';
|
|
6
7
|
|
|
7
8
|
export const frequencyEquals = (a, b) => {
|
|
8
9
|
if (a === null || b === null) return false;
|
|
@@ -62,12 +63,10 @@ export class SelectFrequency extends withChildOptions(FrequencyStatus) {
|
|
|
62
63
|
} else {
|
|
63
64
|
result = this._defaultFrequency;
|
|
64
65
|
}
|
|
66
|
+
|
|
65
67
|
// this runs for shopify selling plans translated to freq
|
|
66
|
-
if (this.frequencies?.length && result && this.config?.frequenciesEveryPeriod) {
|
|
67
|
-
|
|
68
|
-
if (index >= 0) {
|
|
69
|
-
return this.frequencies[index];
|
|
70
|
-
}
|
|
68
|
+
if (this.config?.frequencies?.length && result && this.config?.frequenciesEveryPeriod?.length) {
|
|
69
|
+
return frequencyToSellingPlan(result, this.config);
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
return result;
|
|
@@ -302,25 +302,25 @@ describe('previewMode', () => {
|
|
|
302
302
|
});
|
|
303
303
|
});
|
|
304
304
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
305
|
+
async function getOfferElement(config) {
|
|
306
|
+
const element = new Offer();
|
|
307
|
+
element.innerHTML = `
|
|
308
|
+
<p>Offer content</p>
|
|
309
|
+
`;
|
|
310
|
+
element.config = config;
|
|
311
|
+
await appendToBody(element);
|
|
312
|
+
return element;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function assertOfferShown(element) {
|
|
316
|
+
expect(element.querySelector('*').assignedSlot).not.toBeNull();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function assertOfferHidden(element) {
|
|
320
|
+
expect(element.querySelector('*').assignedSlot).toBeNull();
|
|
321
|
+
}
|
|
323
322
|
|
|
323
|
+
describe('multi-currency', () => {
|
|
324
324
|
it('should show the offer when config not set', async () => {
|
|
325
325
|
const element = await getOfferElement();
|
|
326
326
|
assertOfferShown(element);
|
|
@@ -369,3 +369,22 @@ describe('multi-currency', () => {
|
|
|
369
369
|
assertOfferShown(element);
|
|
370
370
|
});
|
|
371
371
|
});
|
|
372
|
+
|
|
373
|
+
describe('product specific frequencies', () => {
|
|
374
|
+
it('should hide the offer when on cart', async () => {
|
|
375
|
+
const element = await getOfferElement({
|
|
376
|
+
hasProductSpecificFrequencies: true
|
|
377
|
+
});
|
|
378
|
+
element.isCart = true;
|
|
379
|
+
await element.updateComplete;
|
|
380
|
+
|
|
381
|
+
assertOfferHidden(element);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should show the offer when not on cart', async () => {
|
|
385
|
+
const element = await getOfferElement({
|
|
386
|
+
hasProductSpecificFrequencies: true
|
|
387
|
+
});
|
|
388
|
+
assertOfferShown(element);
|
|
389
|
+
});
|
|
390
|
+
});
|
|
@@ -15,12 +15,20 @@ describe('frequencyToSellingPlan', () => {
|
|
|
15
15
|
expect(frequencyToSellingPlan('345', {})).toEqual('345');
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it('should return
|
|
18
|
+
it('should return first frequency if no frequency match', () => {
|
|
19
19
|
expect(
|
|
20
20
|
frequencyToSellingPlan('1_2', {
|
|
21
21
|
frequenciesEveryPeriod: ['1_1', '1_3'],
|
|
22
22
|
frequencies: [123, 789]
|
|
23
23
|
})
|
|
24
|
+
).toEqual(123);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return original frequency if no frequency match and frequenciesEveryPeriod not defined', () => {
|
|
28
|
+
expect(
|
|
29
|
+
frequencyToSellingPlan('1_2', {
|
|
30
|
+
frequencies: [123, 789]
|
|
31
|
+
})
|
|
24
32
|
).toEqual('1_2');
|
|
25
33
|
});
|
|
26
34
|
});
|
package/src/core/utils.ts
CHANGED
|
@@ -70,6 +70,12 @@ export const frequencyToSellingPlan = (ogFrequency, config) => {
|
|
|
70
70
|
return config.frequencies[ix];
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// if we can't find the OG frequency, but we have selling plans, return the first selling plan
|
|
74
|
+
if (config.frequencies?.length > 0 && config.frequenciesEveryPeriod?.length > 0) {
|
|
75
|
+
console.warn(`Unable to find selling plan match for frequency ${ogFrequency}; falling back to first selling plan`);
|
|
76
|
+
return config.frequencies[0];
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
return ogFrequency;
|
|
74
80
|
};
|
|
75
81
|
|
|
@@ -337,7 +337,42 @@ describe('config', () => {
|
|
|
337
337
|
);
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
+
const defaultSellingPlanPayload = {
|
|
341
|
+
product: {
|
|
342
|
+
selling_plan_groups: [
|
|
343
|
+
{
|
|
344
|
+
name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
|
|
345
|
+
selling_plans: [
|
|
346
|
+
{
|
|
347
|
+
id: 'yum selling plan id 1'
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: 'yum selling plan id 2'
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
340
358
|
it('should return selling plan ids as frequencies given action SETUP_PRODUCT', () => {
|
|
359
|
+
const actual = config(
|
|
360
|
+
{},
|
|
361
|
+
{
|
|
362
|
+
type: constants.SETUP_PRODUCT,
|
|
363
|
+
payload: defaultSellingPlanPayload
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(actual).toEqual(
|
|
368
|
+
jasmine.objectContaining({
|
|
369
|
+
frequencies: ['yum selling plan id 1', 'yum selling plan id 2'],
|
|
370
|
+
hasProductSpecificFrequencies: false
|
|
371
|
+
})
|
|
372
|
+
);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it('should return values of first OG selling plan group as frequencies text given action SETUP_PRODUCT', () => {
|
|
341
376
|
const actual = config(
|
|
342
377
|
{},
|
|
343
378
|
{
|
|
@@ -346,13 +381,20 @@ describe('config', () => {
|
|
|
346
381
|
product: {
|
|
347
382
|
selling_plan_groups: [
|
|
348
383
|
{
|
|
349
|
-
name:
|
|
384
|
+
name: 'Old Selling Plan Group',
|
|
385
|
+
options: [{ values: 'old yum values' }],
|
|
350
386
|
selling_plans: [
|
|
351
387
|
{
|
|
352
|
-
id: 'yum selling plan id
|
|
353
|
-
}
|
|
388
|
+
id: 'old yum selling plan id'
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: DEFAULT_PAY_AS_YOU_GO_GROUP_NAME,
|
|
394
|
+
options: [{ values: 'yum values' }],
|
|
395
|
+
selling_plans: [
|
|
354
396
|
{
|
|
355
|
-
id: 'yum selling plan id
|
|
397
|
+
id: 'yum selling plan id'
|
|
356
398
|
}
|
|
357
399
|
]
|
|
358
400
|
}
|
|
@@ -364,12 +406,12 @@ describe('config', () => {
|
|
|
364
406
|
|
|
365
407
|
expect(actual).toEqual(
|
|
366
408
|
jasmine.objectContaining({
|
|
367
|
-
|
|
409
|
+
frequenciesText: 'yum values'
|
|
368
410
|
})
|
|
369
411
|
);
|
|
370
412
|
});
|
|
371
413
|
|
|
372
|
-
it('should
|
|
414
|
+
it('should use product-specific frequency selling plan groups if present', () => {
|
|
373
415
|
const actual = config(
|
|
374
416
|
{},
|
|
375
417
|
{
|
|
@@ -378,20 +420,40 @@ describe('config', () => {
|
|
|
378
420
|
product: {
|
|
379
421
|
selling_plan_groups: [
|
|
380
422
|
{
|
|
381
|
-
name: '
|
|
382
|
-
options: [
|
|
423
|
+
name: 'og_psfl_2m4m6m',
|
|
424
|
+
options: [
|
|
425
|
+
{
|
|
426
|
+
values: ['2 months', '4 months', '6 months']
|
|
427
|
+
}
|
|
428
|
+
],
|
|
383
429
|
selling_plans: [
|
|
384
430
|
{
|
|
385
|
-
id: '
|
|
431
|
+
id: 'psfl-id-1'
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
id: 'psfl-id-2'
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
id: 'psfl-id-3'
|
|
386
438
|
}
|
|
387
439
|
]
|
|
388
440
|
},
|
|
389
441
|
{
|
|
390
|
-
name:
|
|
391
|
-
options: [
|
|
442
|
+
name: 'Subscribe and Save',
|
|
443
|
+
options: [
|
|
444
|
+
{
|
|
445
|
+
values: ['month', '2 months', '3 months']
|
|
446
|
+
}
|
|
447
|
+
],
|
|
392
448
|
selling_plans: [
|
|
393
449
|
{
|
|
394
|
-
id: '
|
|
450
|
+
id: 'regular-id-1'
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
id: 'regular-id-2'
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: 'regular-id-3'
|
|
395
457
|
}
|
|
396
458
|
]
|
|
397
459
|
}
|
|
@@ -403,7 +465,26 @@ describe('config', () => {
|
|
|
403
465
|
|
|
404
466
|
expect(actual).toEqual(
|
|
405
467
|
jasmine.objectContaining({
|
|
406
|
-
|
|
468
|
+
frequencies: ['psfl-id-1', 'psfl-id-2', 'psfl-id-3'],
|
|
469
|
+
hasProductSpecificFrequencies: true
|
|
470
|
+
})
|
|
471
|
+
);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('does not overwrite hasProductSpecificFrequencies on subsequent calls', () => {
|
|
475
|
+
const actual = config(
|
|
476
|
+
{
|
|
477
|
+
hasProductSpecificFrequencies: true
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
type: constants.SETUP_PRODUCT,
|
|
481
|
+
payload: defaultSellingPlanPayload
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
expect(actual).toEqual(
|
|
486
|
+
jasmine.objectContaining({
|
|
487
|
+
hasProductSpecificFrequencies: true
|
|
407
488
|
})
|
|
408
489
|
);
|
|
409
490
|
});
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from '../core/utils';
|
|
34
34
|
|
|
35
35
|
import { getObjectStructuredProductPlans } from '../core/adapters';
|
|
36
|
+
|
|
36
37
|
import {
|
|
37
38
|
sellingPlanAllocationsReducer,
|
|
38
39
|
getSellingPlans,
|
|
@@ -126,12 +127,18 @@ export const reduceNewOptinsFromOfferResponse = (
|
|
|
126
127
|
}, []);
|
|
127
128
|
|
|
128
129
|
const getOGSellingPlanGroup = product => {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
const productSpecificFrequencySellingPlanGroup = product?.selling_plan_groups.find(
|
|
131
|
+
isProductSpecificFrequencySellingPlanGroup
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
productSpecificFrequencySellingPlanGroup ||
|
|
136
|
+
product?.selling_plan_groups.find(group => group.name === DEFAULT_PAY_AS_YOU_GO_GROUP_NAME)
|
|
137
|
+
);
|
|
133
138
|
};
|
|
134
139
|
|
|
140
|
+
const isProductSpecificFrequencySellingPlanGroup = group => group.name.startsWith('og_psfl');
|
|
141
|
+
|
|
135
142
|
const productOrVariantInStockReducer = (acc, cur) => ({
|
|
136
143
|
...overrideLineKey(acc, cur.id, cur.available),
|
|
137
144
|
[cur.id]: cur.available
|
|
@@ -280,7 +287,9 @@ export const config = (
|
|
|
280
287
|
frequencies,
|
|
281
288
|
frequenciesEveryPeriod,
|
|
282
289
|
frequenciesText,
|
|
283
|
-
...(defaultFrequency ? { defaultFrequency } : {})
|
|
290
|
+
...(defaultFrequency ? { defaultFrequency } : {}),
|
|
291
|
+
hasProductSpecificFrequencies:
|
|
292
|
+
state.hasProductSpecificFrequencies || isProductSpecificFrequencySellingPlanGroup(sellingPlanGroup)
|
|
284
293
|
};
|
|
285
294
|
}
|
|
286
295
|
|