UNPKG

@tef-novum/webview-bridge

Version:

JavaScript library to access to native functionality. Requires a webview with a postMessage bridge.

1,207 lines (1,180 loc) 57.1 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.webviewBridge = {})); })(this, (function (exports) { 'use strict'; var messageId = 1; var webviewId = "".concat(Date.now(), "-").concat(String(Math.random()).slice(-8)); /** * Message ID generator. Ids should be unique. * * the "web" prefix indicates that the message was originated from the web side. * * Using a timestamp as webviewId (assuming two webviews are not opened in the same millisecond), * but if that ever happens, the last part is a random number to avoid collisions. */ var getId = function () { return "web-".concat(messageId++, "-").concat(webviewId); }; var _a; var BRIDGE = '__tuenti_webview_bridge'; var hasAndroidPostMessage = function () { return !!(typeof window !== 'undefined' && window.tuentiWebView && window.tuentiWebView.postMessage); }; var hasWebKitPostMessage = function () { return !!(typeof window !== 'undefined' && window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.tuentiWebView && window.webkit.messageHandlers.tuentiWebView.postMessage); }; /** * Maybe returns postMessage function exposed by native apps */ var getWebViewPostMessage = function () { if (typeof window === 'undefined') { return null; } // Android if (hasAndroidPostMessage()) { return function (jsonMessage) { window.tuentiWebView.postMessage(jsonMessage); }; } // iOS if (hasWebKitPostMessage()) { return function (jsonMessage) { window.webkit.messageHandlers.tuentiWebView.postMessage(jsonMessage); }; } return null; }; var messageListeners = []; var subscribe = function (listener) { messageListeners.push(listener); }; var unsubscribe = function (listener) { messageListeners = messageListeners.filter(function (f) { return f !== listener; }); }; var isInIframe = function () { try { return window.self !== window.top; } catch (e) { return true; } }; var isDisabledFromIframe = function () { var _a; if (typeof window === 'undefined') { return false; } if (!isInIframe()) { return false; } return !((_a = window === null || window === void 0 ? void 0 : window.frameElement) === null || _a === void 0 ? void 0 : _a.hasAttribute('data-enable-webview-bridge')); }; var log = undefined; var setLogger = function (logger) { log = logger; }; /** * Returns true if there is a WebView Bridge installed */ var isWebViewBridgeAvailable = function () { return !isDisabledFromIframe() && (hasAndroidPostMessage() || hasWebKitPostMessage()); }; /** * Send message to native app and waits for response */ var postMessageToNativeApp = function (_a, timeout) { var type = _a.type, _b = _a.id, id = _b === void 0 ? getId() : _b, payload = _a.payload; var postMessage = getWebViewPostMessage(); var message = JSON.stringify({ type: type, id: id, payload: payload }); log === null || log === void 0 ? void 0 : log('[WebView Bridge] SEND:', message); if (!postMessage) { return Promise.reject({ code: 500, reason: 'WebView postMessage not available', }); } // ensure postMessage call is async setTimeout(function () { postMessage(message); }); return new Promise(function (resolve, reject) { var timedOut = false; var listener = function (response) { if (response.id === id && !timedOut) { if (response.type === type) { resolve(response.payload); } else if (response.type === 'ERROR') { reject(response.payload); } else { reject({ code: 500, reason: "bad type: ".concat(response.type, ". Expecting ").concat(type), }); } unsubscribe(listener); } }; subscribe(listener); if (timeout) { setTimeout(function () { timedOut = true; unsubscribe(listener); reject({ code: 408, reason: 'request timeout' }); }, timeout); } }); }; /** * Initiates postMessage function, which will be called by native apps */ if (typeof window !== 'undefined') { // if there is already a bridge instance, we need to call it too when we receive a message var prevPostMessageImplementation_1 = (_a = window[BRIDGE]) === null || _a === void 0 ? void 0 : _a.postMessage; window[BRIDGE] = { postMessage: function (jsonMessage) { prevPostMessageImplementation_1 === null || prevPostMessageImplementation_1 === void 0 ? void 0 : prevPostMessageImplementation_1(jsonMessage); log === null || log === void 0 ? void 0 : log('[WebView Bridge] RCVD:', jsonMessage); var message; try { message = JSON.parse(jsonMessage); } catch (e) { throw Error("Problem parsing webview message: ".concat(jsonMessage)); } messageListeners.forEach(function (f) { return f(message); }); }, }; } var listenToNativeMessage = function (type, handler) { var listener = function (message) { if (message.type === type) { Promise.resolve(handler(message.payload)).then(function (responsePayload) { var postMessage = getWebViewPostMessage(); if (postMessage) { postMessage(JSON.stringify({ type: message.type, id: message.id, payload: responsePayload, })); } }); } }; subscribe(listener); return function () { unsubscribe(listener); }; }; var nativeConfirm = function (_a) { var message = _a.message, title = _a.title, acceptText = _a.acceptText, cancelText = _a.cancelText, destructive = _a.destructive; if (isWebViewBridgeAvailable()) { return postMessageToNativeApp({ type: 'CONFIRM', payload: { message: message, title: title, acceptText: acceptText, cancelText: cancelText, destructive: destructive }, }).then(function (_a) { var result = _a.result; return result; }); } else { return Promise.resolve(typeof window === 'undefined' ? false : window.confirm(message)); } }; var nativeAlert = function (_a) { var message = _a.message, title = _a.title, buttonText = _a.buttonText; if (isWebViewBridgeAvailable()) { return postMessageToNativeApp({ type: 'ALERT', payload: { title: title, message: message, buttonText: buttonText }, }); } else { if (typeof window !== 'undefined') { window.alert(message); } return Promise.resolve(); } }; var nativeMessage = function (_a) { var message = _a.message, duration = _a.duration, buttonText = _a.buttonText, buttonAccessibilityLabel = _a.buttonAccessibilityLabel, type = _a.type, withDismiss = _a.withDismiss; if (isWebViewBridgeAvailable()) { return postMessageToNativeApp({ type: 'MESSAGE', payload: { message: message, duration: duration, buttonText: buttonText, buttonAccessibilityLabel: buttonAccessibilityLabel, type: type, withDismiss: withDismiss, }, }).then(function (response) { // old app versions didn't return a response or returned a response without action if (!response || !response.action) { return { action: 'DISMISS', }; } return response; }); } else { if (typeof window !== 'undefined') { window.alert(message); } return Promise.resolve({ action: 'DISMISS' }); } }; var TIMEOUT = 200; /** @deprecated */ var requestSimIcc = function () { return postMessageToNativeApp({ type: 'SIM_ICC' }, TIMEOUT) .then(function (response) { return response.icc; }) .catch(function () { return null; }); }; /** @deprecated */ var requestSimImsi = function () { return postMessageToNativeApp({ type: 'IMSI' }, TIMEOUT) .then(function (response) { return response.imsi; }) .catch(function () { return null; }); }; var requestDeviceImei = function () { return postMessageToNativeApp({ type: 'IMEI' }, TIMEOUT) .then(function (response) { return response.imei; }) .catch(function () { return null; }); }; var internalNavigation = function (feature) { return postMessageToNativeApp({ type: 'INTERNAL_NAVIGATION', payload: { feature: feature, }, }); }; var dismiss = function (onCompletionUrl) { return postMessageToNativeApp({ type: 'DISMISS', payload: { onCompletionUrl: onCompletionUrl, }, }); }; var requestVibration = function (type) { return postMessageToNativeApp({ type: 'VIBRATION', payload: { type: type, }, }); }; var getDiskSpaceInfo = function () { return postMessageToNativeApp({ type: 'GET_DISK_SPACE_INFO', }); }; var getEsimInfo = function () { return postMessageToNativeApp({ type: 'GET_ESIM_INFO', }).catch(function () { return ({ supportsEsim: false, eid: null, }); }); }; var getAttStatus = function () { return postMessageToNativeApp({ type: 'GET_ATT_STATUS', }).catch(function () { return null; }); }; var getDeviceModel = function () { return postMessageToNativeApp({ type: 'MODEL', }).catch(function () { return null; }); }; var getDeviceTac = function () { return postMessageToNativeApp({ type: 'TAC', }).catch(function () { return ({ tac: null }); }); }; var shareBase64 = function (params) { return postMessageToNativeApp({ type: 'SHARE_BASE64', payload: { content: params.contentInBase64, fileName: params.fileName, }, }); }; var downloadBase64 = function (params) { return postMessageToNativeApp({ type: 'DOWNLOAD_BASE64', payload: { content: params.contentInBase64, fileName: params.fileName, }, }); }; var getBatteryInfo = function () { return postMessageToNativeApp({ type: 'GET_BATTERY_INFO' }); }; var getInstallationId = function () { return postMessageToNativeApp({ type: 'GET_INSTALLATION_ID' }); }; /** * Get the current status of the biometrics authentication on the device. * * Possible results: * - 'DISABLED': The device has an authentication method (device PIN code at least, and biometrics optionally) but it has the biometrics option disabled in the app * - 'ENABLED': The device has an authentication method (device PIN code at least, and biometrics optionally) and it has the biometrics option enabled in the app (it requires authentication when launching the app) * - 'DEVICE_HAS_NO_AUTHENTICATION': The device has not any authentication method (it has no device PIN code neither biometrics) * * Error cases: * - 404: The bridge implementation does not support this feature * - 500: User is not logged in */ var getBiometricsAuthenticationStatus = function () { return postMessageToNativeApp({ type: 'GET_BIOMETRICS_AUTHENTICATION_STATUS', }); }; /** * Set the current status of the biometrics authentication on the device. * * Possible request based on 'enable': * - false: Disable biometrics in the app and remove any related information * - true: Trigger the biometrics enabling native UI * * Error cases: * - 400: enable parameter is missing * - 500: Native side error while applying the setting * - 503: The device has no biometrics available, or the user cancelled modifying biometric settings. */ var setBiometricsAuthenticationStatus = function (params) { return postMessageToNativeApp({ type: 'SET_BIOMETRICS_AUTHENTICATION_STATUS', payload: { enable: params.enable, }, }); }; /** * Opens a native OCR scanner that looks for text matching the provided regular expression. * When a text is found matching the pattern, the scanner closes and returns the scanned text. * Only the first text that matches the pattern will be returned. * * The scanner will attempt to request camera permissions automatically. * Only available in Mein Blau and Mein O2. * * Error cases: * - 401: Missing permissions (user rejected camera permissions) * - 405: Feature not supported in current brand (only available in Mein Blau and Mein O2) * - 500: Internal error (e.g., unexpected error thrown by native scanner) * * @param params.regex - Regular expression pattern to match the scanned text * @returns Promise that resolves to an object containing the scanned text or null if user closed the scanner */ var openOcrScanner = function (params) { return postMessageToNativeApp({ type: 'OPEN_OCR_SCANNER', payload: { regex: params.regex, timeoutMs: params.timeoutMs, }, }); }; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(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()); }); } function __generator(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 (_) 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 attachToEmail = function (_a) { var url = _a.url, subject = _a.subject, fileName = _a.fileName, recipient = _a.recipient, body = _a.body; return postMessageToNativeApp({ type: 'ATTACH_TO_EMAIL', payload: { url: url, subject: subject, fileName: fileName, recipient: recipient, body: body }, }); }; var share = function (options) { return postMessageToNativeApp({ type: 'SHARE', payload: options, }); }; /** * Related doc: https://confluence.tid.es/pages/viewpage.action?spaceKey=CTO&title=%5BAPPS%5D+Shared+Spec%3A+Top+Bar+customization#id-[APPS]SharedSpec:TopBarcustomization-Tracking */ var updateNavigationBar = function (options) { if (isWebViewBridgeAvailable()) { return postMessageToNativeApp({ type: 'NAVIGATION_BAR', payload: options, }); } else { if (options.title !== undefined && typeof document !== 'undefined') { document.title = options.title; } return Promise.resolve(); } }; /** * Returns the unsubscribe function. Should be called when the component is unmounted. */ var onNavigationBarIconClicked = function (handler) { return listenToNativeMessage('NAVIGATION_BAR_ICON_CLICKED', handler); }; /** * @deprecated */ var setWebViewTitle = function (title) { if (isWebViewBridgeAvailable()) { return updateNavigationBar({ title: title }); } else { if (typeof document !== 'undefined') { document.title = title; } return Promise.resolve(); } }; var notifyPageLoaded = function () { return postMessageToNativeApp({ type: 'PAGE_LOADED' }); }; var notifyBridgeReady = function () { return postMessageToNativeApp({ type: 'BRIDGE_READY' }); }; var remoteConfig = null; var isRemoteConfigAvailable = function (key) { return remoteConfig.result[key] === 'true'; }; var getRemoteConfig = function () { if (!remoteConfig) { // If GET_REMOTE_CONFIG takes more than 5s to respond resolve with empty result var timeoutP = new Promise(function (resolve) { setTimeout(function () { resolve({ result: {} }); }, 500); }); var configP = postMessageToNativeApp({ type: 'GET_REMOTE_CONFIG', }).then(function (res) { remoteConfig = res; return __assign({}, remoteConfig); }); return Promise.race([timeoutP, configP]); } else { return Promise.resolve(__assign({}, remoteConfig)); } }; var isABTestingAvailable = function (key) { return getRemoteConfig() .then(function () { return isRemoteConfigAvailable(key); }) .catch(function () { return false; }); }; var reportStatus = function (_a) { var feature = _a.feature, status = _a.status, reason = _a.reason; return postMessageToNativeApp({ type: 'STATUS_REPORT', payload: { feature: feature, status: status, reason: reason }, }); }; var fetch = function (_a) { var url = _a.url, method = _a.method, headers = _a.headers, body = _a.body; return postMessageToNativeApp({ type: 'FETCH', payload: { url: url, method: method, headers: headers, body: body }, }).catch(function () { return ({ status: 500, headers: {}, body: 'Bridge call failed', }); }); }; var checkPermissionStatus = function (feature, params) { return postMessageToNativeApp({ type: 'OS_PERMISSION_STATUS', payload: { feature: feature, params: params, }, }).then(function (_a) { var granted = _a.granted; return granted; }); }; var getAppMetadata = function (appToken) { return postMessageToNativeApp({ type: 'GET_APP_METADATA', payload: { appToken: appToken, }, }); }; var getNetworkConnectionInfo = function () { return postMessageToNativeApp({ type: 'DATA_CONNECTION_INFO', payload: {}, }); }; var setActionBehavior = function (actions) { return postMessageToNativeApp({ type: 'SET_ACTION_BEHAVIOR', payload: { actions: actions, }, }).catch(function () { // do nothing }); }; /** * Returns the Topaz SDK Token * https://www.topaz.com.br/ofd/index.php */ var getTopazToken = function (options) { if (options === void 0) { options = {}; } return postMessageToNativeApp({ type: 'GET_TOPAZ_TOKEN', payload: {}, }, options.timeout); }; var getTopazValues = function () { return postMessageToNativeApp({ type: 'GET_TOPAZ_VALUES', payload: {}, }); }; var getPincodeInfo = function () { return postMessageToNativeApp({ type: 'GET_PINCODE_INFO' }); }; var triggerPinOrBiometricAuthentication = function (maxSecondsSinceLastValidation) { return postMessageToNativeApp({ type: 'TRIGGER_PIN_OR_BIOMETRIC_AUTHENTICATION', payload: { maxSecondsSinceLastValidation: maxSecondsSinceLastValidation }, }); }; var focusNavbar = function () { return postMessageToNativeApp({ type: 'FOCUS_NAVBAR' }); }; var showLoadingOverlay = function (payload) { return postMessageToNativeApp({ type: 'SHOW_LOADING_OVERLAY', payload: payload }); }; var hideLoadingOverlay = function () { return postMessageToNativeApp({ type: 'HIDE_LOADING_OVERLAY' }); }; var msToS = function (ms) { return Math.floor(ms / 1000); }; var createCalendarEvent = function (_a) { var beginTime = _a.beginTime, endTime = _a.endTime, title = _a.title; return postMessageToNativeApp({ type: 'CREATE_CALENDAR_EVENT', payload: { beginTime: msToS(beginTime), endTime: msToS(endTime), title: title, }, }); }; var requestContact = function (_a) { var _b = _a === void 0 ? {} : _a, _c = _b.filter, filter = _c === void 0 ? 'phone' : _c; return postMessageToNativeApp({ type: 'GET_CONTACT_DATA', payload: { filter: filter } }); }; var fetchContactsByPhone = function (phoneNumbers) { return postMessageToNativeApp({ type: 'FETCH_CONTACTS_DATA', payload: { phoneNumbers: phoneNumbers }, }); }; var fetchPhoneNumbers = function () { return postMessageToNativeApp({ type: 'FETCH_PHONE_NUMBERS', }); }; var updatePhoneNumbers = function (phoneNumbers) { return postMessageToNativeApp({ type: 'UPDATE_PHONE_NUMBERS', payload: { phoneNumbers: phoneNumbers }, }); }; var addOrEditContact = function (phoneNumber) { return postMessageToNativeApp({ type: 'ADD_OR_EDIT_CONTACT', payload: { phoneNumber: phoneNumber }, }); }; var highlightNavigationTab = function (_a) { var tab = _a.tab, highlight = _a.highlight, count = _a.count; return postMessageToNativeApp({ type: 'HIGHLIGHT_TAB', payload: { tab: tab, highlight: highlight, count: count, }, }); }; /** @deprecated */ var CD_WEBAPP_INSTALLED = 4; /** @deprecated */ var CD_NOVUM_UID = 7; /** @deprecated */ var CD_EVENT_VALUE = 8; var DEFAULT_EVENT_LABEL = 'null_label'; var DEFAULT_EVENT_VALUE = 0; var CALLBACK_TIMEOUT = 500; var MAX_TIMEOUT_TIMES = 3; var timeoutCounter = 0; var createCallback = function (resolve) { // Analytics may fail to load (for example, if blocked by an adblocker). If that happens, we still need to resolve // the logEvent promises, so we stablish a timeout for those cases. // If the log times out more than MAX_TIMEOUT_TIMES times consecutively, we don't try to send more events and inmediately resolve // all the promises. var tid = setTimeout(function () { resolve(); timeoutCounter++; }, CALLBACK_TIMEOUT); return function () { clearTimeout(tid); timeoutCounter = 0; resolve(); }; }; var withAnalytics = function (_a) { var onAndroid = _a.onAndroid, onIos = _a.onIos, onWeb = _a.onWeb; if (typeof window === 'undefined') { return Promise.resolve(); } if (window.AnalyticsWebInterface) { // Call Android interface return onAndroid(window.AnalyticsWebInterface); } else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.firebase) { // Call iOS interface return onIos(window.webkit.messageHandlers.firebase); } else if ( // @ts-ignore TS thinks gtag is always available, but it may not be the case if the page has not loaded the gtag script window.gtag && timeoutCounter < MAX_TIMEOUT_TIMES) { // Use Google Analytics when webapp is outside the native app webview return onWeb(window.gtag); } else { return Promise.resolve(); } }; var removeAccents = function (str) { // Normalize to NFD (normal form decomposition) and delete Combining Diacritical Marks Unicode // https://stackoverflow.com/a/37511463/3874587 return str.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); }; var EVENT_PARAM_NAME_CHARS_LIMIT = 40; var EVENT_PARAM_VALUE_CHARS_LIMIT = 100; var EVENT_PARAMS_LIMIT = 25; var sanitizeAnalyticsParam = function (str) { return removeAccents(str) .toLocaleLowerCase() .replace(/[^a-zß0-9\s\-\_\/\|\:]/g, '') // Remove all non allowed characters .replace(/\s+/g, ' ') // Replace repeated whitespaces with a single space .trim() .replace(/\s/g, '_') // Replace spaces with underscores .slice(0, EVENT_PARAM_VALUE_CHARS_LIMIT); }; var sanitizeAnalyticsParams = function (params) { var sanitizedParams = {}; Object.entries(params).forEach(function (entry) { var key = entry[0]; var value = entry[1]; var sanitizedValue = value; var sanitizedKey = key.slice(0, EVENT_PARAM_NAME_CHARS_LIMIT); if (typeof value === 'string') { // Some string params may contain strings with accents (some of them may be copies/translations), so we need to sanitize them sanitizedValue = sanitizeAnalyticsParam(value); } sanitizedParams[sanitizedKey] = sanitizedValue; }); return sanitizedParams; }; var getLegacyAnalyticsEventParams = function (_a) { var category = _a.category, action = _a.action, label = _a.label, value = _a.value, fieldsObject = __rest(_a, ["category", "action", "label", "value"]); if (!label) { label = DEFAULT_EVENT_LABEL; } if (!value) { value = DEFAULT_EVENT_VALUE; } return __assign({ eventCategory: category, eventAction: action, eventLabel: removeAccents(label), eventValue: value }, fieldsObject); }; var defaultEventOptions = { sanitize: true }; var currentScreenName = ''; var logEvent = function (event, options) { var sanitize = __assign(__assign({}, defaultEventOptions), options).sanitize; var name = event.name, params = __rest(event, ["name"]); // If the event doesn't have a name, it's a legacy analytics event if (!name) { if (!event.category || !event.action) { console.warn('LegacyAnalyticsEvent should have "category" and "action"', { category: event.category, action: event.action, }); return Promise.resolve(); } params = getLegacyAnalyticsEventParams(event); name = event.category; } else { if (Object.keys(params).length > EVENT_PARAMS_LIMIT) { console.warn("Trying to log FirebaseEvent with name ".concat(name, " exceeding the limit of ").concat(EVENT_PARAMS_LIMIT, " params")); } if (sanitize) { params = sanitizeAnalyticsParams(params); name = sanitizeAnalyticsParam(name); } } // set screen name if not set params = __assign(__assign({}, params), { screenName: params.screenName || currentScreenName }); return withAnalytics({ onAndroid: function (androidFirebase) { if (androidFirebase.logEvent) { androidFirebase.logEvent(name, JSON.stringify(params)); } return Promise.resolve(); }, onIos: function (iosFirebase) { iosFirebase.postMessage({ command: 'logEvent', name: name, parameters: params, }); return Promise.resolve(); }, onWeb: function (gtag) { return new Promise(function (resolve) { gtag('event', name, __assign(__assign({}, params), { event_callback: createCallback(resolve) })); }); }, }); }; var logEcommerceEvent = function (name, params) { // set screen name if not set params = __assign(__assign({}, params), { screenName: params.screenName || currentScreenName }); return withAnalytics({ onAndroid: function (androidFirebase) { if (androidFirebase.logEvent) { androidFirebase.logEvent(name, JSON.stringify(params)); } return Promise.resolve(); }, onIos: function (iosFirebase) { iosFirebase.postMessage({ command: 'logEvent', name: name, parameters: params, }); return Promise.resolve(); }, onWeb: function () { // not implemented on web return Promise.resolve(); }, }); }; var logTiming = function (_a) { var _b = _a.category, category = _b === void 0 ? 'performance_timer' : _b, variable = _a.variable, value = _a.value, label = _a.label; if (!category || !variable || !value) { console.warn('Analytics timing should have "category", "variable" and "value"', { category: category, variable: variable, value: value }); return Promise.resolve(); } value = Math.round(value); var params = { timingCategory: category, timingVar: variable, timingValue: value, timingLabel: label, }; var name = category; return withAnalytics({ onAndroid: function (androidFirebase) { if (androidFirebase.logEvent) { androidFirebase.logEvent(name, JSON.stringify(params)); } return Promise.resolve(); }, onIos: function (iosFirebase) { iosFirebase.postMessage({ command: 'logEvent', name: name, parameters: params, }); return Promise.resolve(); }, onWeb: function () { return new Promise(function (resolve) { gtag('event', name, __assign(__assign({}, params), { event_callback: createCallback(resolve) })); }); }, }); }; var setScreenName = function (screenName, params, options) { if (params === void 0) { params = {}; } if (!screenName) { console.warn('Missing analytics screenName'); return Promise.resolve(); } var sanitize = __assign(__assign({}, defaultEventOptions), options).sanitize; var previousScreenName = currentScreenName; currentScreenName = screenName; var sanitizedParams = sanitize ? sanitizeAnalyticsParams(params) : params; return withAnalytics({ onAndroid: function (androidFirebase) { // The method to send params with the screen name is only implemented in new app versions. if (androidFirebase.setScreenNameWithParams) { androidFirebase.setScreenNameWithParams(screenName, JSON.stringify(sanitizedParams)); } else if (androidFirebase.setScreenName) { androidFirebase.setScreenName(screenName); } return Promise.resolve(); }, onIos: function (iosFirebase) { iosFirebase.postMessage({ command: 'setScreenName', name: screenName, parameters: sanitizedParams, }); return Promise.resolve(); }, onWeb: function (gtag) { return new Promise(function (resolve) { gtag('event', 'page_view', __assign(__assign({ screenName: screenName, page_title: screenName, previousScreenName: previousScreenName }, sanitizedParams), { event_callback: createCallback(resolve) })); }); }, }); }; var setUserProperty = function (name, value) { if (!name || !value) { console.warn('Trying to set analytics user property without name or value', name, value); return Promise.resolve(); } value = String(value); return withAnalytics({ onAndroid: function (androidFirebase) { if (androidFirebase.setUserProperty) { androidFirebase.setUserProperty(name, value); } return Promise.resolve(); }, onIos: function (iosFirebase) { iosFirebase.postMessage({ command: 'setUserProperty', name: name, value: value, }); return Promise.resolve(); }, onWeb: function (gtag) { var _a; gtag('set', 'user_properties', (_a = {}, _a[name] = sanitizeAnalyticsParam(value), _a)); return Promise.resolve(); }, }); }; var setTrackingProperty = function (system, name, value) { return postMessageToNativeApp({ type: 'SET_TRACKING_PROPERTY', payload: { system: system, name: name, value: value, }, }).catch(function () { // do nothing }); }; /** * This method is used by webapp to request the native app to renew current session * When webapp (running inside a webview) receives a 401 api response from server, uses this * bridge method to renew the session. */ var renewSession = function (oldAccessToken, options) { if (options === void 0) { options = {}; } return postMessageToNativeApp({ type: 'RENEW_SESSION', payload: { accessToken: oldAccessToken || null }, }, options.timeout).then(function (result) { return result.accessToken; }); }; /** * This method is used to listen for session renewals made by native app. Whenever the native app * renews the session with the api, it should notify webpp with this message. * This message is initiated by native app. */ var onSessionRenewed = function (handler) { return listenToNativeMessage('SESSION_RENEWED', function (result) { return handler(result.accessToken); }); }; /** * This method is used by webapp to request the native app to end the current session */ var logout = function () { return postMessageToNativeApp({ type: 'LOG_OUT' }); }; /** * This method is used by webapp to request the native app to launch the app rating dialog */ var showAppRating = function () { return postMessageToNativeApp({ type: 'SHOW_APP_RATING' }); }; var sheetLock = false; var bottomSheet = function (payload) { if (sheetLock) { return Promise.reject({ code: 423, reason: 'BottomSheet is locked. You can only have one bottom sheet in the screen', }); } sheetLock = true; var tid = setTimeout(function () { sheetLock = false; }, 1000); return postMessageToNativeApp({ type: 'SHEET', payload: payload }) .then(function (response) { sheetLock = false; clearTimeout(tid); return response; }) .catch(function (e) { sheetLock = false; clearTimeout(tid); throw e; }); }; /** * This method is used by webapp to request the native app to launch the app rating dialog */ var openOnboarding = function () { return postMessageToNativeApp({ type: 'OPEN_ONBOARDING' }); }; var getProfileImage = function () { return postMessageToNativeApp({ type: 'GET_PROFILE_IMAGE', }); }; var startProfileImageFlow = function () { return postMessageToNativeApp({ type: 'START_PROFILE_IMAGE_FLOW', }); }; var showLineSelector = function () { return postMessageToNativeApp({ type: 'SHOW_LINE_SELECTOR', }); }; /** * These functions try to use the Web Clipboard API if available, otherwise fall back to the bridge * implementation in native apps. * * According to the tests done, the Web Clipboard API works fine in iOS webviews but fails with a permissions * error in Android in some cases. Also, old versions of Chrome in Android may not have support for the Web * Clipboard API at all. * * We have decided to not implement the bridge method in iOS apps, as the Web Clipboard API works fine. */ var readTextFromClipboard = function () { var _a; return (((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.readText) ? navigator.clipboard.readText() : Promise.reject()).catch(function () { return postMessageToNativeApp({ type: 'CLIPBOARD_READ_TEXT' }); }); }; var writeTextToClipboard = function (text) { var _a; return (((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText) ? navigator.clipboard.writeText(text) : Promise.reject()).catch(function () { return postMessageToNativeApp({ type: 'CLIPBOARD_WRITE_TEXT', payload: text, }); }); }; var getUnseenNotificationsBadge = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, postMessageToNativeApp({ type: 'GET_UNSEEN_NOTIFICATIONS_BADGE' })]; }); }); }; var setUnseenNotificationsBadge = function (payload) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, postMessageToNativeApp({ type: 'SET_UNSEEN_NOTIFICATIONS_BADGE', payload: payload })]; }); }); }; var requestDatamobDeviceAdmin = function () { return postMessageToNativeApp({ type: 'REQUEST_DATAMOB_DEVICE_ADMIN', payload: {}, }).then(function (_a) { var isAdmin = _a.isAdmin; return ({ isAdmin: isAdmin }); }); }; var registerDatamobUser = function (_a) { var phoneNumber = _a.phoneNumber, tokenPassword = _a.tokenPassword; return postMessageToNativeApp({ type: 'REGISTER_DATAMOB_USER', payload: { phoneNumber: phoneNumber, tokenPassword: tokenPassword }, }); }; var validateDatamobRequirements = function (_a) { var phoneNumber = _a.phoneNumber, tokenPassword = _a.tokenPassword; return postMessageToNativeApp({ type: 'VALIDATE_DATAMOB_REQUIREMENTS', payload: { phoneNumber: phoneNumber, tokenPassword: tokenPassword }, }); }; var unregisterDatamobDeviceAdmin = function () { return postMessageToNativeApp({ type: 'UNREGISTER_DATAMOB_DEVICE_ADMIN' }); }; var displayQualtricsIntercept = function (_a) { var interceptId = _a.interceptId; return postMessageToNativeApp({ type: 'DISPLAY_QUALTRICS_INTERCEPT', payload: { interceptId: interceptId }, }); }; var setQualtricsProperties = function (_a) { var _b = _a.stringProperties, stringProperties = _b === void 0 ? {} : _b, _c = _a.numberProperties, numberProperties = _c === void 0 ? {} : _c, _d = _a.dateTimePropertyKeys, dateTimePropertyKeys = _d === void 0 ? [] : _d; return postMessageToNativeApp({ type: 'SET_QUALTRICS_PROPERTIES', payload: { stringProperties: stringProperties, numberProperties: numberProperties, dateTimePropertyKeys: dateTimePropertyKeys }, }); }; var isQualtricsInterceptAvailableForUser = function (_a) { var interceptId = _a.interceptId; return postMessageToNativeApp({ type: 'IS_QUALTRICS_INTERCEPT_AVAILABLE_FOR_USER', payload: { interceptId: interceptId }, }); }; var AllowMeGenericError = 500; var AllowMeUnauthorizedError = 401; var AllowMeSetupSdkError = 1001; var AllowMeTimeoutProcessingError = 1002; var AllowMeApiKeyError = 1003; var AllowMeInstanceCreationError = 1004; var AllowMeBiometricsTimeoutError = 1005; var AllowMeBiometricsSetupError = 1006; var AllowMeBiometricsCameraError = 1007; var AllowMeBiometricsCapturingError = 1008; var AllowMeBiometricsResultError = 1009; var AllowMeBiometricsCancelledByUserError = 1010; var AllowMeBiometricsInvalidImagesError = 1011; var AllowMeBiometricsCameraPermissionError = 1012; var AllowMeCanNotOpenFrontCameraError = 1013; var AllowMeGooglePayServicesError = 1014; var AllowMeFaceDetectionError = 1015; var AllowMeProviderError = 1016; var AllowMeCanNotSaveImageError = 1017; var requestAllowMeBiometrics = function () { return postMessageToNativeApp({ type: 'REQUEST_ALLOWME_BIOMETRICS' }); }; var setupLocatorSdkConfig = function (config) { return postMessageToNativeApp({ type: 'SETUP_LOCATOR_SDK_CONFIG', payload: { config: config, }, }); }; var getLocatorSdkState = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_SDK_STATE' }); }; var setLocatorSdkMode = function (mode) { return postMessageToNativeApp({ type: 'SET_LOCATOR_SDK_MODE', payload: { mode: mode, }, }); }; var getLocatorJwtToken = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_JWT_TOKEN' }); }; var getLocatorPendingPermissions = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_PENDING_PERMISSIONS' }); }; var getLocatorSdkVersion = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_SDK_VERSION' }); }; var getLocatorSdkSession = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_SDK_SESSION' }); }; var getLocatorSdkMode = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_SDK_MODE' }); }; var getLocatorSdkConfig = function () { return postMessageToNativeApp({ type: 'GET_LOCATOR_SDK_CONFIG', }); }; var requestPermissionLocation = function () { return postMessageToNativeApp({ type: 'REQUEST_PERMISSION_LOCATION' }); }; var requestPermissionBackgroundLocation = function () { return postMessageToNativeApp({ type: 'REQUEST_PERMISSION_BACKGROUND_LOCATION' }); }; var requestPermissionMicrophone = function () { return postMessageToNativeApp({ type: 'REQUEST_PERMISSION_MICROPHONE' }); }; var requestPermissionNotifications = function () { return postMessag