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';