Skip to content

Commit de6d338

Browse files
[nextjs] Add support for fallback point of sale (#1367)
* add support for fallback point of sale * lint package * configurable pos resolver for personalize middleware * convert point of sale resolver into a class * cleanup nextjs utils export * fix build issues, add more comments + changelog
1 parent b022482 commit de6d338

File tree

8 files changed

+107
-7
lines changed

8 files changed

+107
-7
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Our versioning strategy is as follows:
1919
* `import { editingDataService } from '@sitecore-jss/sitecore-jss-nextjs/editing';`
2020
* `import { EditingRenderMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/editing';`
2121

22+
* `[sitecore-jss-nextjs] [templates/nextjs-personalize]` getPointOfSale function passed into personalize middleware now accepts two parameters: site and language. Personalize middleware will use a built-in resolver if no function is passed.
23+
2224
* `[sitecore-jss-angular][templates/angular]` jss-angular package and sample has been updated to version 14. This means several changes:
2325
* JSS Angular sample is now using Ivy
2426
* IE11 no longer supported by JSS Angular

packages/create-sitecore-jss/src/templates/nextjs-personalize/src/components/CdpPageView.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
LayoutServicePageState,
44
SiteInfo,
55
useSitecoreContext,
6+
PosResolver
67
} from '@sitecore-jss/sitecore-jss-nextjs';
78
import { useEffect } from 'react';
89
import config from 'temp/config';
@@ -29,9 +30,7 @@ const CdpPageView = (): JSX.Element => {
2930
site: SiteInfo,
3031
pageVariantId: string
3132
) => {
32-
const pointOfSale = site.pointOfSale
33-
? site.pointOfSale[language] || site.pointOfSale[site.language]
34-
: '';
33+
const pointOfSale = PosResolver.resolve(site, language);
3534
const engage = await init({
3635
clientKey: process.env.NEXT_PUBLIC_CDP_CLIENT_KEY || '',
3736
targetURL: process.env.NEXT_PUBLIC_CDP_TARGET_URL || '',

packages/create-sitecore-jss/src/templates/nextjs-personalize/src/lib/middleware/plugins/personalize.ts

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class PersonalizePlugin implements MiddlewarePlugin {
5050
excludeRoute: () => false,
5151
// Site resolver implementation
5252
siteResolver,
53+
// Personalize middleware will use PosResolver.resolve(site, language) (same as CdpPageView) by default to get point of sale.
54+
// You can also pass a custom point of sale resolver into middleware to override it like so:
55+
// getPointOfSale: (site, language) => { ... }
5356
});
5457
}
5558

packages/sitecore-jss-nextjs/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export {
6565
getPersonalizedRewriteData,
6666
normalizePersonalizedRewrite,
6767
CdpHelper,
68+
PosResolver,
6869
} from '@sitecore-jss/sitecore-jss/personalize';
6970
export { GraphQLRequestClient } from '@sitecore-jss/sitecore-jss';
7071

packages/sitecore-jss-nextjs/src/middleware/personalize-middleware.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import {
77
ExperienceParams,
88
getPersonalizedRewrite,
99
} from '@sitecore-jss/sitecore-jss/personalize';
10-
import { SiteResolver } from '@sitecore-jss/sitecore-jss/site';
10+
import { SiteInfo, SiteResolver } from '@sitecore-jss/sitecore-jss/site';
1111
import { debug, NativeDataFetcher } from '@sitecore-jss/sitecore-jss';
12+
import { PosResolver } from '@sitecore-jss/sitecore-jss/personalize';
1213

1314
export type PersonalizeMiddlewareConfig = {
1415
/**
@@ -43,6 +44,13 @@ export type PersonalizeMiddlewareConfig = {
4344
* @default localhost
4445
*/
4546
defaultHostname?: string;
47+
/**
48+
* function to resolve point of sale for a site
49+
* @param {Siteinfo} site to get info from
50+
* @param {string} language to get info for
51+
* @returns point of sale value for site/language combination
52+
*/
53+
getPointOfSale?: (site: SiteInfo, language: string) => string;
4654
};
4755

4856
/**
@@ -235,9 +243,9 @@ export class PersonalizeMiddleware {
235243
// Execute targeted experience in CDP
236244
const { ua } = userAgent(req);
237245
const params = this.getExperienceParams(req);
238-
const pointOfSale = site.pointOfSale
239-
? site.pointOfSale[language] || site.pointOfSale[site.language]
240-
: '';
246+
const pointOfSale = this.config.getPointOfSale
247+
? this.config.getPointOfSale(site, language)
248+
: PosResolver.resolve(site, language);
241249
const variantId = await this.cdpService.executeExperience(
242250
personalizeInfo.contentId,
243251
browserId,

packages/sitecore-jss/src/personalize/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { personalizeLayout } from './layout-personalizer';
2+
export { PosResolver } from './pos-resolver';
23
export {
34
GraphQLPersonalizeService,
45
GraphQLPersonalizeServiceConfig,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { expect } from 'chai';
2+
import { SiteInfo } from '../site';
3+
import { PosResolver } from './pos-resolver';
4+
5+
describe('resolvePointOfSale', () => {
6+
it('should return empty when no point of sale present', () => {
7+
const site: SiteInfo = {
8+
name: 'no-pos',
9+
hostName: 'www.nopos.com',
10+
language: 'en',
11+
};
12+
const language = 'en';
13+
const result = PosResolver.resolve(site, language);
14+
expect(result).to.equal('');
15+
});
16+
17+
it('should return pos for provided language', () => {
18+
const myPoint = 'apos.com';
19+
const site: SiteInfo = {
20+
name: 'apos',
21+
hostName: 'www.apos.com',
22+
pointOfSale: {
23+
en: myPoint,
24+
},
25+
language: 'de-DE',
26+
};
27+
28+
const result = PosResolver.resolve(site, 'en');
29+
expect(result).to.equal(myPoint);
30+
});
31+
32+
it('should return pos for site language as first backup', () => {
33+
const site: SiteInfo = {
34+
name: 'apos',
35+
hostName: 'www.apos.com',
36+
pointOfSale: {
37+
'de-DE': 'depos.com',
38+
'es-ES': 'espos.com',
39+
},
40+
language: 'de-DE',
41+
};
42+
43+
const result = PosResolver.resolve(site, 'en');
44+
expect(result).to.equal('depos.com');
45+
});
46+
47+
it('should return pos for site language when provided language is empty', () => {
48+
const site: SiteInfo = {
49+
name: 'apos',
50+
hostName: 'www.apos.com',
51+
pointOfSale: {
52+
'de-DE': 'depos.com',
53+
'es-ES': 'espos.com',
54+
},
55+
language: 'de-DE',
56+
};
57+
58+
const result = PosResolver.resolve(site, '');
59+
expect(result).to.equal('depos.com');
60+
});
61+
62+
it('should use fallback value when other values missing', () => {
63+
const site: SiteInfo = {
64+
name: 'apos',
65+
hostName: 'www.apos.com',
66+
pointOfSale: {
67+
'de-DE': 'depos.com',
68+
'es-ES': 'espos.com',
69+
'*': 'fallpos.com',
70+
},
71+
language: 'en-CA',
72+
};
73+
74+
const result = PosResolver.resolve(site, 'en');
75+
expect(result).to.equal('fallpos.com');
76+
});
77+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { SiteInfo } from '../site';
2+
3+
export class PosResolver {
4+
static resolve = (site: SiteInfo, language: string) => {
5+
return site.pointOfSale
6+
? site.pointOfSale[language] || site.pointOfSale[site.language] || site.pointOfSale['*']
7+
: '';
8+
};
9+
}

0 commit comments

Comments
 (0)