import { SURVEYS } from './constants';
import { getSurveySeenStorageKeys } from './extensions/surveys/surveys-utils';
import { Info } from './utils/event-utils';
import { assignableWindow, document, userAgent, window } from './utils/globals';
import { createLogger } from './utils/logger';
import { isMatchingRegex } from './utils/regex-utils';
import { SurveyEventReceiver } from './utils/survey-event-receiver';
import { isNullish } from './utils/type-utils';
var logger = createLogger('[Surveys]');
export var surveyValidationMap = {
icontains: function (targets, value) { return targets.some(function (target) { return value.toLowerCase().includes(target.toLowerCase()); }); },
not_icontains: function (targets, value) { return targets.every(function (target) { return !value.toLowerCase().includes(target.toLowerCase()); }); },
regex: function (targets, value) { return targets.some(function (target) { return isMatchingRegex(value, target); }); },
not_regex: function (targets, value) { return targets.every(function (target) { return !isMatchingRegex(value, target); }); },
exact: function (targets, value) { return targets.some(function (target) { return value === target; }); },
is_not: function (targets, value) { return targets.every(function (target) { return value !== target; }); },
};
function defaultMatchType(matchType) {
return matchType !== null && matchType !== void 0 ? matchType : 'icontains';
}
// use urlMatchType to validate url condition, fallback to contains for backwards compatibility
export function doesSurveyUrlMatch(survey) {
var _a, _b, _c;
if (!((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.url)) {
return true;
}
// if we dont know the url, assume it is not a match
var href = (_b = window === null || window === void 0 ? void 0 : window.location) === null || _b === void 0 ? void 0 : _b.href;
if (!href) {
return false;
}
var targets = [survey.conditions.url];
return surveyValidationMap[defaultMatchType((_c = survey.conditions) === null || _c === void 0 ? void 0 : _c.urlMatchType)](targets, href);
}
export function doesSurveyDeviceTypesMatch(survey) {
var _a, _b, _c;
if (!((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.deviceTypes) || ((_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.deviceTypes.length) === 0) {
return true;
}
// if we dont know the device type, assume it is not a match
if (!userAgent) {
return false;
}
var deviceType = Info.deviceType(userAgent);
return surveyValidationMap[defaultMatchType((_c = survey.conditions) === null || _c === void 0 ? void 0 : _c.deviceTypesMatchType)](survey.conditions.deviceTypes, deviceType);
}
var PostHogSurveys = /** @class */ (function () {
function PostHogSurveys(instance) {
this.instance = instance;
this._isFetchingSurveys = false;
this._isInitializingSurveys = false;
// we set this to undefined here because we need the persistence storage for this type
// but that's not initialized until loadIfEnabled is called.
this._surveyEventReceiver = null;
}
PostHogSurveys.prototype.onRemoteConfig = function (response) {
this._decideServerResponse = !!response['surveys'];
logger.info("decideServerResponse set to ".concat(this._decideServerResponse));
this.loadIfEnabled();
};
PostHogSurveys.prototype.reset = function () {
localStorage.removeItem('lastSeenSurveyDate');
var surveyKeys = getSurveySeenStorageKeys();
surveyKeys.forEach(function (key) { return localStorage.removeItem(key); });
};
PostHogSurveys.prototype.loadIfEnabled = function () {
var _this = this;
if (this._surveyManager) {
// Surveys already loaded.
return;
}
if (this._isInitializingSurveys) {
logger.info('Already initializing surveys, skipping...');
return;
}
var disableSurveys = this.instance.config.disable_surveys;
if (disableSurveys) {
logger.info('Disabled. Not loading surveys.');
return;
}
var phExtensions = assignableWindow === null || assignableWindow === void 0 ? void 0 : assignableWindow.__PosthogExtensions__;
if (!phExtensions) {
logger.error('PostHog Extensions not found.');
return;
}
if (!this._decideServerResponse) {
logger.warn('Decide not loaded yet. Not loading surveys.');
return;
}
this._isInitializingSurveys = true;
try {
var generateSurveys = phExtensions.generateSurveys;
if (!generateSurveys) {
var loadExternalDependency = phExtensions.loadExternalDependency;
if (loadExternalDependency) {
loadExternalDependency(this.instance, 'surveys', function (err) {
if (err || !phExtensions.generateSurveys) {
logger.error('Could not load surveys script', err);
_this._isInitializingSurveys = false;
return;
}
_this._surveyManager = phExtensions.generateSurveys(_this.instance);
_this._isInitializingSurveys = false;
_this._surveyEventReceiver = new SurveyEventReceiver(_this.instance);
logger.info('Surveys loaded successfully');
});
}
else {
logger.error('PostHog loadExternalDependency extension not found. Cannot load remote config.');
this._isInitializingSurveys = false;
}
}
else {
this._surveyManager = generateSurveys(this.instance);
this._isInitializingSurveys = false;
this._surveyEventReceiver = new SurveyEventReceiver(this.instance);
logger.info('Surveys loaded successfully');
}
}
catch (e) {
logger.error('Error initializing surveys', e);
this._isInitializingSurveys = false;
throw e;
}
};
PostHogSurveys.prototype.getSurveys = function (callback, forceReload) {
var _this = this;
if (forceReload === void 0) { forceReload = false; }
// In case we manage to load the surveys script, but config says not to load surveys
// then we shouldn't return survey data
if (this.instance.config.disable_surveys) {
logger.info('Disabled. Not loading surveys.');
return callback([]);
}
var existingSurveys = this.instance.get_property(SURVEYS);
if (!existingSurveys || forceReload) {
// Prevent concurrent API calls
if (this._isFetchingSurveys) {
return callback([]);
}
try {
this._isFetchingSurveys = true;
this.instance._send_request({
url: this.instance.requestRouter.endpointFor('api', "/api/surveys/?token=".concat(this.instance.config.token)),
method: 'GET',
timeout: this.instance.config.surveys_request_timeout_ms,
callback: function (response) {
var _a;
var _b, _c;
_this._isFetchingSurveys = false;
var statusCode = response.statusCode;
if (statusCode !== 200 || !response.json) {
logger.error("Surveys API could not be loaded, status: ".concat(statusCode));
return callback([]);
}
var surveys = response.json.surveys || [];
var eventOrActionBasedSurveys = surveys.filter(function (survey) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
return (((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.events) &&
((_c = (_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.events) === null || _c === void 0 ? void 0 : _c.values) &&
((_f = (_e = (_d = survey.conditions) === null || _d === void 0 ? void 0 : _d.events) === null || _e === void 0 ? void 0 : _e.values) === null || _f === void 0 ? void 0 : _f.length) > 0) ||
(((_g = survey.conditions) === null || _g === void 0 ? void 0 : _g.actions) &&
((_j = (_h = survey.conditions) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.values) &&
((_m = (_l = (_k = survey.conditions) === null || _k === void 0 ? void 0 : _k.actions) === null || _l === void 0 ? void 0 : _l.values) === null || _m === void 0 ? void 0 : _m.length) > 0);
});
if (eventOrActionBasedSurveys.length > 0) {
(_b = _this._surveyEventReceiver) === null || _b === void 0 ? void 0 : _b.register(eventOrActionBasedSurveys);
}
(_c = _this.instance.persistence) === null || _c === void 0 ? void 0 : _c.register((_a = {}, _a[SURVEYS] = surveys, _a));
return callback(surveys);
},
});
}
catch (e) {
this._isFetchingSurveys = false;
throw e;
}
}
else {
return callback(existingSurveys);
}
};
PostHogSurveys.prototype.isSurveyFeatureFlagEnabled = function (flagKey) {
if (!flagKey) {
return true;
}
return this.instance.featureFlags.isFeatureEnabled(flagKey);
};
PostHogSurveys.prototype.getActiveMatchingSurveys = function (callback, forceReload) {
var _this = this;
if (forceReload === void 0) { forceReload = false; }
this.getSurveys(function (surveys) {
var _a;
var activeSurveys = surveys.filter(function (survey) {
return !!(survey.start_date && !survey.end_date);
});
var conditionMatchedSurveys = activeSurveys.filter(function (survey) {
var _a;
if (!survey.conditions) {
return true;
}
var urlCheck = doesSurveyUrlMatch(survey);
var selectorCheck = ((_a = survey.conditions) === null || _a === void 0 ? void 0 : _a.selector)
? document === null || document === void 0 ? void 0 : document.querySelector(survey.conditions.selector)
: true;
var deviceTypeCheck = doesSurveyDeviceTypesMatch(survey);
return urlCheck && selectorCheck && deviceTypeCheck;
});
// get all the surveys that have been activated so far with user actions.
var activatedSurveys = (_a = _this._surveyEventReceiver) === null || _a === void 0 ? void 0 : _a.getSurveys();
var targetingMatchedSurveys = conditionMatchedSurveys.filter(function (survey) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
if (!survey.linked_flag_key &&
!survey.targeting_flag_key &&
!survey.internal_targeting_flag_key &&
!((_a = survey.feature_flag_keys) === null || _a === void 0 ? void 0 : _a.length)) {
return true;
}
var linkedFlagCheck = _this.isSurveyFeatureFlagEnabled(survey.linked_flag_key);
var targetingFlagCheck = _this.isSurveyFeatureFlagEnabled(survey.targeting_flag_key);
var hasEvents = ((_e = (_d = (_c = (_b = survey.conditions) === null || _b === void 0 ? void 0 : _b.events) === null || _c === void 0 ? void 0 : _c.values) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0) > 0;
var hasActions = ((_j = (_h = (_g = (_f = survey.conditions) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.values) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : 0) > 0;
var eventBasedTargetingFlagCheck = hasEvents || hasActions ? activatedSurveys === null || activatedSurveys === void 0 ? void 0 : activatedSurveys.includes(survey.id) : true;
var overrideInternalTargetingFlagCheck = _this._canActivateRepeatedly(survey);
var internalTargetingFlagCheck = overrideInternalTargetingFlagCheck ||
_this.isSurveyFeatureFlagEnabled(survey.internal_targeting_flag_key);
var flagsCheck = _this.checkFlags(survey);
return (linkedFlagCheck &&
targetingFlagCheck &&
internalTargetingFlagCheck &&
eventBasedTargetingFlagCheck &&
flagsCheck);
});
return callback(targetingMatchedSurveys);
}, forceReload);
};
PostHogSurveys.prototype.checkFlags = function (survey) {
var _this = this;
var _a;
if (!((_a = survey.feature_flag_keys) === null || _a === void 0 ? void 0 : _a.length)) {
return true;
}
return survey.feature_flag_keys.every(function (_a) {
var key = _a.key, value = _a.value;
if (!key || !value) {
return true;
}
return _this.instance.featureFlags.isFeatureEnabled(value);
});
};
// this method is lazily loaded onto the window to avoid loading preact and other dependencies if surveys is not enabled
PostHogSurveys.prototype._canActivateRepeatedly = function (survey) {
var _a;
if (isNullish((_a = assignableWindow.__PosthogExtensions__) === null || _a === void 0 ? void 0 : _a.canActivateRepeatedly)) {
logger.warn('init was not called');
return false; // TODO does it make sense to have a default here?
}
return assignableWindow.__PosthogExtensions__.canActivateRepeatedly(survey);
};
PostHogSurveys.prototype.canRenderSurvey = function (surveyId) {
var _this = this;
if (isNullish(this._surveyManager)) {
logger.warn('init was not called');
return;
}
this.getSurveys(function (surveys) {
var survey = surveys.filter(function (x) { return x.id === surveyId; })[0];
_this._surveyManager.canRenderSurvey(survey);
});
};
PostHogSurveys.prototype.renderSurvey = function (surveyId, selector) {
var _this = this;
if (isNullish(this._surveyManager)) {
logger.warn('init was not called');
return;
}
this.getSurveys(function (surveys) {
var survey = surveys.filter(function (x) { return x.id === surveyId; })[0];
_this._surveyManager.renderSurvey(survey, document === null || document === void 0 ? void 0 : document.querySelector(selector));
});
};
return PostHogSurveys;
}());
export { PostHogSurveys };
//# sourceMappingURL=posthog-surveys.js.map