@cliqdigital/bloomreach-sdk
Version:
React component library for integrating Bloomreach SDK with push notifications support
250 lines (249 loc) • 16.7 kB
JavaScript
;
'use client';
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NextBloomreachProvider = void 0;
var react_1 = __importDefault(require("react"));
var BloomreachContext_1 = require("../context/BloomreachContext");
var NotificationHandler_1 = require("./NotificationHandler");
var NextBloomreachProvider = /** @class */ (function (_super) {
__extends(NextBloomreachProvider, _super);
function NextBloomreachProvider(props) {
var _this = _super.call(this, props) || this;
_this.requestNotificationPermission = function () { return __awaiter(_this, void 0, void 0, function () {
var result, e_1;
var _a, _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
_e.trys.push([0, 3, , 4]);
if (!this.state.browserSupported) {
console.log('Browser does not support notifications, skipping permission request');
return [2 /*return*/];
}
if (!(typeof Notification !== 'undefined')) return [3 /*break*/, 2];
return [4 /*yield*/, Notification.requestPermission()];
case 1:
result = _e.sent();
if (result === 'granted') {
console.log('Notification permission granted');
this.setState({ hasConsent: true });
// Track the consent event with the correct format
window.exponea.track("consent", {
category: "browser_notifications",
action: "accept",
timestamp: new Date().toISOString(),
valid_until: "unlimited",
source: "public_api",
identification_type: "cookie"
});
// Track the specific push notification event
window.exponea.track('push_notification_consent', {
status: 'granted',
timestamp: new Date().toISOString()
});
(_b = (_a = this.props.config).onConsentGranted) === null || _b === void 0 ? void 0 : _b.call(_a);
}
else {
this.setState({ hasConsent: false });
// Track the consent event with the correct format
window.exponea.track("consent", {
category: "browser_notifications",
action: "reject",
timestamp: new Date().toISOString(),
source: "public_api",
identification_type: "cookie"
});
(_d = (_c = this.props.config).onConsentDenied) === null || _d === void 0 ? void 0 : _d.call(_c);
}
_e.label = 2;
case 2: return [3 /*break*/, 4];
case 3:
e_1 = _e.sent();
console.error('Error requesting notification permission:', e_1);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); };
_this.state = {
isInitialized: false,
error: null,
isClient: false,
hasConsent: false,
browserSupported: true
};
return _this;
}
NextBloomreachProvider.prototype.componentDidMount = function () {
var _this = this;
this.setState({
isClient: true,
browserSupported: this.checkBrowserSupport()
}, function () {
_this.initializeSDK();
});
};
// Check if the browser supports push notifications
NextBloomreachProvider.prototype.checkBrowserSupport = function () {
if (typeof window === 'undefined')
return false;
// iOS Safari detection
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
// Push notifications are not supported on iOS Safari
if (isIOS && isSafari) {
console.log('iOS Safari detected - push notifications not supported');
return false;
}
// Check if notifications API is available
if (!('Notification' in window)) {
console.log('Notifications API not supported in this browser');
return false;
}
// Check if service workers are supported
if (!('serviceWorker' in navigator)) {
console.log('Service Workers not supported in this browser');
return false;
}
return true;
};
NextBloomreachProvider.prototype.initializeSDK = function () {
return __awaiter(this, void 0, void 0, function () {
var config_1, script;
var _this = this;
return __generator(this, function (_a) {
try {
config_1 = this.props.config;
if (!config_1.projectToken) {
throw new Error('Bloomreach project token is missing');
}
if (typeof window !== 'undefined') {
script = document.createElement('script');
script.type = 'text/javascript';
script.innerHTML = "\n !function(e,n,t,i,r,o){function s(e){if(\"number\"!=typeof e)return e;var n=new Date;return new Date(n.getTime()+1e3*e)}var a=4e3,c=\"xnpe_async_hide\";function p(e){return e.reduce((function(e,n){return e[n]=function(){e._.push([n.toString(),arguments])},e}),{_:[]})}function m(e,n,t){var i=t.createElement(n);i.src=e;var r=t.getElementsByTagName(n)[0];return r.parentNode.insertBefore(i,r),i}function u(e){return\"[object Date]\"===Object.prototype.toString.call(e)}o.target=o.target||\"https://api.exponea.com\",o.file_path=o.file_path||o.target+\"/js/exponea.min.js\",r[n]=p([\"anonymize\",\"initialize\",\"identify\",\"getSegments\",\"update\",\"track\",\"trackLink\",\"trackEnhancedEcommerce\",\"getHtml\",\"showHtml\",\"showBanner\",\"showWebLayer\",\"ping\",\"getAbTest\",\"loadDependency\",\"getRecommendation\",\"reloadWebLayers\",\"_preInitialize\",\"_initializeConfig\"]),r[n].notifications=p([\"isAvailable\",\"isSubscribed\",\"subscribe\",\"unsubscribe\"]),r[n].segments=p([\"subscribe\"]),r[n][\"snippetVersion\"]=\"v2.7.0\",function(e,n,t){e[n][\"_\"+t]={},e[n][\"_\"+t].nowFn=Date.now,e[n][\"_\"+t].snippetStartTime=e[n][\"_\"+t].nowFn()}(r,n,\"performance\"),function(e,n,t,i,r,o){e[r]={sdk:e[i],sdkObjectName:i,skipExperiments:!!t.new_experiments,sign:t.token+\"/\"+(o.exec(n.cookie)||[\"\",\"new\"])[1],path:t.target}}(r,e,o,n,i,RegExp(\"__exponea_etc__\"+\"=([\\w-]+)\")),function(e,n,t){m(e.file_path,n,t)}(o,t,e),function(e,n,t,i,r,o,p){if(e.new_experiments){!0===e.new_experiments&&(e.new_experiments={});var l,f=e.new_experiments.hide_class||c,_=e.new_experiments.timeout||a,g=encodeURIComponent(o.location.href.split(\"#\")[0]);e.cookies&&e.cookies.expires&&(\"number\"==typeof e.cookies.expires||u(e.cookies.expires)?l=s(e.cookies.expires):e.cookies.expires.tracking&&(\"number\"==typeof e.cookies.expires.tracking||u(e.cookies.expires.tracking))&&(l=s(e.cookies.expires.tracking))),l&&l<new Date&&(l=void 0);var d=e.target+\"/webxp/\"+n+\"/\"+o[t].sign+\"/modifications.min.js?http-referer=\"+g+\"&timeout=\"+_+\"ms\"+(l?\"&cookie-expires=\"+Math.floor(l.getTime()/1e3):\"\");\"sync\"===e.new_experiments.mode&&o.localStorage.getItem(\"__exponea__sync_modifications__\")?function(e,n,t,i,r){t[r][n]=\"<\"+n+' src=\"'+e+'\"></'+n+\">\",i.writeln(t[r][n]),i.writeln(\"<\"+n+\">!\"+r+\".init && document.writeln(\"+r+\".\"+n+'.replace(\"/'+n+'/\", \"/'+n+'-async/\").replace(\"><\", \" async><\"))</'+n+\">\")}(d,n,o,p,t):function(e,n,t,i,r,o,s,a){o.documentElement.classList.add(e);var c=m(t,i,o);function p(){r[a].init||m(t.replace(\"/\"+i+\"/\",\"/\"+i+\"-async/\"),i,o)}function u(){o.documentElement.classList.remove(e)}c.onload=p,c.onerror=p,r.setTimeout(u,n),r[s]._revealPage=u}(f,_,d,n,o,p,r,t)}}(o,t,i,0,n,r,e),function(e,n,t){var i;e[n]._initializeConfig(t),(null===(i=t.experimental)||void 0===i?void 0:i.non_personalized_weblayers)&&e[n]._preInitialize(t),e[n].start=function(i){i&&Object.keys(i).forEach((function(e){return t[e]=i[e]})),e[n].initialize(t)}}(r,n,o)}(document,\"exponea\",\"script\",\"webxpClient\",window,{\n target: \"https://eu2-api.eng.bloomreach.com\",\n token: \"".concat(config_1.projectToken, "\",\n experimental: {\n non_personalized_weblayers: true,\n },\n track: {\n google_analytics: false,\n },\n });\n window.exponea.start();\n console.log('Bloomreach SDK initialized with official snippet');\n ");
document.head.appendChild(script);
// Track page view after initialization
setTimeout(function () {
if (window.exponea) {
// Update customer properties with host information
var customerData = {
host: window.location.host,
last_visit: new Date().toISOString(),
url: window.location.href,
referrer: document.referrer || 'direct',
browser: navigator.userAgent,
push_notifications_supported: _this.state.browserSupported
};
window.exponea.update(customerData);
console.log('Customer properties updated with host:', customerData);
// Mark as initialized
_this.setState({ isInitialized: true }, function () {
var _a;
// Set up notifications if needed
if (_this.state.browserSupported &&
((_a = config_1.notifications) === null || _a === void 0 ? void 0 : _a.requestPermissionOnLoad) &&
Notification.permission === 'default') {
_this.requestNotificationPermission();
}
});
}
}, 1000); // Allow time for the SDK to initialize
}
}
catch (error) {
console.error('Error initializing SDK:', error);
this.setState({ error: error });
}
return [2 /*return*/];
});
});
};
NextBloomreachProvider.prototype.render = function () {
var _this = this;
if (!this.state.isClient) {
return null;
}
if (this.state.error) {
console.error('SDK initialization error:', this.state.error);
return null;
}
return (react_1.default.createElement(BloomreachContext_1.BloomreachContext.Provider, { value: {
isInitialized: this.state.isInitialized,
hasConsent: this.state.hasConsent,
browserSupported: this.state.browserSupported,
setHasConsent: function (consent) {
var _a, _b;
_this.setState({ hasConsent: consent });
(_b = (_a = _this.props.config).onConsentGranted) === null || _b === void 0 ? void 0 : _b.call(_a);
},
config: this.props.config
} },
react_1.default.createElement(NotificationHandler_1.NotificationHandler, { onConsentGranted: function () {
var _a, _b;
_this.setState({ hasConsent: true });
(_b = (_a = _this.props.config).onConsentGranted) === null || _b === void 0 ? void 0 : _b.call(_a);
}, onConsentDenied: function () {
var _a, _b;
_this.setState({ hasConsent: false });
(_b = (_a = _this.props.config).onConsentDenied) === null || _b === void 0 ? void 0 : _b.call(_a);
} }),
this.props.children));
};
return NextBloomreachProvider;
}(react_1.default.Component));
exports.NextBloomreachProvider = NextBloomreachProvider;