From 892e6d1a5f1f6bf09112686dc95eedaf68f0c223 Mon Sep 17 00:00:00 2001 From: Yavor Krastev <4502045+yavorsk@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:09:44 +0200 Subject: [PATCH] [angular][xmcloud] CDP page view component (#1957) * remove duplicate changelog entry * add cdp page view component to send page view events * minor update of imports * update changelog * some fixes - handle empty language, handle send event error; * do not initialize csdk and send events if not in production mode * add comment Co-authored-by: Illia Kovalenko <23364749+illiakovalenko@users.noreply.github.com> * fix comment intendation * minor update of changelog entry Co-authored-by: Illia Kovalenko <23364749+illiakovalenko@users.noreply.github.com> * rename personalize scop environment variable * add migration guide entry for page view tracking * add migrate guide for cloud sdk init * update changelog * remove 'public' prefix of the personalize scope env variable --------- Co-authored-by: Illia Kovalenko <23364749+illiakovalenko@users.noreply.github.com> --- CHANGELOG.md | 3 +- docs/upgrades/unreleased.md | 62 +++++++++++++++ .../src/templates/angular-xmcloud/.env | 7 ++ .../scripts/cdp-page-view.component.ts | 77 +++++++++++++++++++ .../scripts/cloud-sdk-init.component.ts | 6 +- .../routing/scripts/scripts.component.html | 1 + .../src/app/routing/scripts/scripts.module.ts | 3 +- .../sitecore-jss-angular/src/public_api.ts | 2 + 8 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cdp-page-view.component.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d2a83b083d..582ba0a68f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,7 +72,8 @@ Our versioning strategy is as follows: * `[template/node-xmcloud-proxy]` `[sitecore-jss-proxy]` Introduced /api/healthz endpoint ([#1928](https://github.com/Sitecore/jss/pull/1928)) * `[sitecore-jss]` `[sitecore-jss-angular]` Render field metdata chromes in editMode metadata - in edit mode metadata in Pages, angular package field directives will render wrapping `code` elements with field metadata required for editing; ([#1926](https://github.com/Sitecore/jss/pull/1926)) * `[angular-xmcloud]``[sitecore-jss-angular]` Analytics and CloudSDK integration -* `[angular-xmcloud]` Add CloudSDK initialization on client side ([#1952](https://github.com/Sitecore/jss/pull/1952)) + * `[angular-xmcloud]` Add CloudSDK initialization on client side ([#1952](https://github.com/Sitecore/jss/pull/1952))([#1957](https://github.com/Sitecore/jss/pull/1957)) + * `[angular-xmcloud]``[sitecore-jss-angular]` Add CDP Page View component to Angular XM Cloud add-on ([#1957](https://github.com/Sitecore/jss/pull/1957)) ### 🛠 Breaking Change diff --git a/docs/upgrades/unreleased.md b/docs/upgrades/unreleased.md index ee86877c1d..1ba6496bf1 100644 --- a/docs/upgrades/unreleased.md +++ b/docs/upgrades/unreleased.md @@ -293,7 +293,69 @@ If you plan to use the Angular SDK with XMCloud, you will need to perform next s ], ``` +* In XMCloud client side event tracking is done via CloudSDK so you need to make sure that it is initialized before send any event. See the following example of a component that does that; note that it should be added to the scripts.component.html before any other scripts that uses it; for more details take a look at the OOTB cloud-sdk-init.component.ts: + ```ts + import { CloudSDK } from '@sitecore-cloudsdk/core/browser'; + import '@sitecore-cloudsdk/events/browser'; + import { environment } from '../../../environments/environment'; + import { isServer } from '@sitecore-jss/sitecore-jss-angular'; + ... + ngOnInit(): void { + if (!isServer() && environment.production) { + CloudSDK({ + siteName: environment.sitecoreSiteName, + sitecoreEdgeUrl: environment.sitecoreEdgeUrl, + sitecoreEdgeContextId: environment.sitecoreEdgeContextId, + cookieDomain: window.location.hostname.replace(/^www\./, ''), + enableBrowserCookie: true, + }) + .addEvents() + .initialize(); + } + } + ``` + * scripts.component.html: + + ```html + + ``` + +* In order to be able to track Page View events in XMCloud you have to add a component that executes the page view event and render it in the scripts section; in XMCloud client side event tracking is done via CloudSDK so you need to make sure that it is initialized before firing any tracked event. + * see example code below; for more details take a look at the OOTB cdp-page-view.component.ts + + ```ts + import { JssContextService } from '../../jss-context.service'; + import { JssState } from '../../JssState'; + import { pageView, PageViewData } from '@sitecore-cloudsdk/events/browser'; + ... + ngOnInit(): void { + if (!isServer()) { + this.contextSubscription = this.jssContext.state.subscribe((newState: JssState) => { + ... + // prepare the required data + ... + + const pageViewData: PageViewData = { + channel: 'WEB', + currency: 'USD', + page: route.name, + pageVariantId, + language, + }; + + pageView(pageViewData).catch((err) => console.debug(err)); + }); + } + } + ``` + + * add the component to the scripts.component.html after the CloudSdk initialize component: + + ```html + + + ``` # @sitecore-jss/sitecore-jss-proxy diff --git a/packages/create-sitecore-jss/src/templates/angular-xmcloud/.env b/packages/create-sitecore-jss/src/templates/angular-xmcloud/.env index d76ee32482..6be3add8eb 100644 --- a/packages/create-sitecore-jss/src/templates/angular-xmcloud/.env +++ b/packages/create-sitecore-jss/src/templates/angular-xmcloud/.env @@ -12,3 +12,10 @@ PROXY_HOST=http://localhost:3000 # Your XM Cloud Proxy server path is needed to build the app. The build output will be copied to the proxy server path. PROXY_BUILD_PATH=<%- locals.relativeProxyAppDestination.replace(/\\/g, '\\\\') %>dist + +# ============================================== + +# An optional Sitecore Personalize scope identifier. +# This can be used to isolate personalization data when multiple XM Cloud Environments share a Personalize tenant. +# This should match the PAGES_PERSONALIZE_SCOPE environment variable for your connected XM Cloud Environment. +PERSONALIZE_SCOPE= diff --git a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cdp-page-view.component.ts b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cdp-page-view.component.ts new file mode 100644 index 0000000000..b30a270559 --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cdp-page-view.component.ts @@ -0,0 +1,77 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { isServer, CdpHelper, LayoutServicePageState } from '@sitecore-jss/sitecore-jss-angular'; +import { pageView, PageViewData } from '@sitecore-cloudsdk/events/browser'; +import { JssContextService } from '../../jss-context.service'; +import { JssState } from '../../JssState'; +import { environment } from '../../../environments/environment'; + +/** + * This is the CDP page view component. + * It uses the Sitecore Cloud SDK to enable page view events on the client-side. + * See Sitecore Cloud SDK documentation for details. + * https://www.npmjs.com/package/@sitecore-cloudsdk/events + */ +@Component({ + selector: 'app-cdp-page-view', + template: '', +}) +export class CdpPageViewComponent implements OnInit, OnDestroy { + private contextSubscription: Subscription; + + constructor(private jssContext: JssContextService) {} + + ngOnInit(): void { + if (!isServer()) { + this.contextSubscription = this.jssContext.state.subscribe((newState: JssState) => { + const { + route, + context: { pageState, language, variantId }, + } = newState.sitecore; + + // Do not create events in editing or preview mode or if missing route data + if (pageState !== LayoutServicePageState.Normal || !route?.itemId) { + return; + } + + // Do not create events if disabled (e.g. we don't have consent) + if (this.disabled()) { + return; + } + + const scope = process.env.PERSONALIZE_SCOPE; + const pageVariantId = CdpHelper.getPageVariantId( + route.itemId, + language || environment.defaultLanguage, + variantId as string, + scope + ); + + const pageViewData: PageViewData = { + channel: 'WEB', + currency: 'USD', + page: route.name, + pageVariantId, + language, + }; + + pageView(pageViewData).catch((err) => console.debug(err)); + }); + } + } + + ngOnDestroy() { + if (this.contextSubscription) { + this.contextSubscription.unsubscribe(); + } + } + + /** + * Determines if the page view events should be turned off. + * IMPORTANT: You should implement based on your cookie consent management solution of choice. + * By default it is disabled if not in production mode + */ + disabled = () => { + return !environment.production; + }; +} diff --git a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cloud-sdk-init.component.ts b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cloud-sdk-init.component.ts index 8a99ae3c06..9801861595 100644 --- a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cloud-sdk-init.component.ts +++ b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/cloud-sdk-init.component.ts @@ -15,7 +15,7 @@ export class CloudSdkInitComponent implements OnInit { constructor() {} ngOnInit(): void { - if (!isServer) { + if (!isServer() && environment.production) { CloudSDK({ siteName: environment.sitecoreSiteName, sitecoreEdgeUrl: environment.sitecoreEdgeUrl, @@ -25,8 +25,8 @@ export class CloudSdkInitComponent implements OnInit { // Cookie may be created in personalize middleware (server), but if not we should create it here enableBrowserCookie: true, }) - .addEvents() - .initialize(); + .addEvents() + .initialize(); } } } diff --git a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.component.html b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.component.html index c39b8b6e85..caed1a4cf6 100644 --- a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.component.html +++ b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.component.html @@ -1,4 +1,5 @@ + diff --git a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.module.ts b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.module.ts index 1b25306864..26d09c93c1 100644 --- a/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.module.ts +++ b/packages/create-sitecore-jss/src/templates/angular-xmcloud/src/app/routing/scripts/scripts.module.ts @@ -2,10 +2,11 @@ import { NgModule } from '@angular/core'; import { ScriptsComponent } from './scripts.component'; import { JssModule } from '@sitecore-jss/sitecore-jss-angular'; import { CloudSdkInitComponent } from './cloud-sdk-init.component'; +import { CdpPageViewComponent } from './cdp-page-view.component'; @NgModule({ exports: [ScriptsComponent], imports: [JssModule], - declarations: [ScriptsComponent, CloudSdkInitComponent], + declarations: [ScriptsComponent, CloudSdkInitComponent, CdpPageViewComponent], }) export class ScriptsModule {} diff --git a/packages/sitecore-jss-angular/src/public_api.ts b/packages/sitecore-jss-angular/src/public_api.ts index 3dd1deea43..c5df6b590d 100644 --- a/packages/sitecore-jss-angular/src/public_api.ts +++ b/packages/sitecore-jss-angular/src/public_api.ts @@ -50,6 +50,7 @@ export { LayoutService, LayoutServiceData, LayoutServiceContextData, + LayoutServicePageState, GraphQLLayoutService, RestLayoutService, PlaceholdersData, @@ -103,3 +104,4 @@ export { EventInstance, PageViewInstance, } from '@sitecore-jss/sitecore-jss/tracking'; +export { CdpHelper } from '@sitecore-jss/sitecore-jss/personalize';