UNPKG

grovs

Version:

Grovs generates dynamic links, tracks attributions, and analyzes referrals, seamlessly directing users to your app or the app store for downloads.

99 lines (76 loc) 62.7 kB
/* * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). * This devtool is neither made for production nor for readable output files. * It uses "eval()" calls to create a separate source file in the browser devtools. * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) * or disable the default devtool with "devtool: false". * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Grovs"] = factory(); else root["Grovs"] = factory(); })(this, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./src/grovs.js": /*!**********************!*\ !*** ./src/grovs.js ***! \**********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_manager_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_manager.js */ \"./src/grovs_manager.js\");\n\n\n/**\n * Entry point for the Grovs SDK.\n * Provides methods to initialize and interact with the SDK.\n */\nclass Grovs {\n /**\n * Creates an instance of the Grovs SDK.\n * @param {string} APIKey - The API key for authentication.\n * @param {boolean} testEnvironment - Indicates if the environment is a test environment.\n * @param {Function} linkHandlingCallback - Callback function to handle Grovs data.\n */\n constructor(APIKey, testEnvironment, linkHandlingCallback) {\n // Initialize the GrovsManager with the provided API key and callback\n this.manager = new _grovs_manager_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"](\n APIKey,\n testEnvironment,\n linkHandlingCallback\n );\n }\n\n /**\n * Starts the Grovs SDK by authenticating with the API.\n * Optionally takes a callback that is called upon successful authentication.\n * @param {Function} [succesfullAuthenticatedCallback=null] - Callback to invoke on successful authentication.\n */\n start(succesfullAuthenticatedCallback = null) {\n // Start authentication process\n this.manager.authenticate(succesfullAuthenticatedCallback);\n }\n\n /**\n * Creates a link with the Grovs API.\n * @param {string} title - The title of the link.\n * @param {string} subtitle - The subtitle of the link.\n * @param {string} imageURL - The URL of the image associated with the link.\n * @param {Object} data - Additional data for the link.\n * @param {Function} success - Success callback for creating the link.\n * @param {Function} error - Error callback for creating the link.\n */\n createLink(title, subtitle, imageURL, data, success, error) {\n // Delegate link creation to the manager\n this.manager.createLink(title, subtitle, imageURL, data, success, error);\n }\n\n /**\n * Retrieves the user identifier from the manager.\n * @returns {string|null} The user identifier, or null if not set.\n */\n userIdentifier() {\n // Get user identifier from the manager\n return this.manager.userIdentifier();\n }\n\n /**\n * Retrieves the user attributes from the manager.\n * @returns {Object|null} The user attributes, or null if not set.\n */\n userAttributes() {\n // Get user attributes from the manager\n return this.manager.userAttributes();\n }\n\n /**\n * Sets the user identifier in the manager.\n * @param {string} identifier - The user identifier to set.\n * @returns {void}\n */\n setUserIdentifier(identifier) {\n // Set user identifier through the manager\n this.manager.setUserIdentifier(identifier);\n }\n\n /**\n * Sets the user attributes in the manager.\n * @param {Object} attributes - A dictionary of user attributes to set.\n * @returns {void}\n */\n setUserAttributes(attributes) {\n // Set user attributes through the manager\n this.manager.setUserAttributes(attributes);\n }\n\n /**\n * Checks if the SDK is authenticated.\n * This method returns the authentication status of the SDK.\n * @returns {boolean} - The authentication status of the manager.\n */\n authenticated() {\n // Return the authentication status from the manager\n return this.manager.authenticated;\n }\n\n /**\n * Displays the messages list using the manager.\n * This method triggers the display of the messages list in the UI.\n * @returns {void}\n */\n showMessagesList() {\n // Delegate message list display to the manager\n this.manager.showMessagesList();\n }\n\n /**\n * Retrieves messages for a specific page using the manager.\n * @param {number} page - The page number to retrieve messages from.\n * @param {Function} response - Callback to handle the retrieved messages.\n * @param {Function} error - Callback to handle any errors during retrieval.\n * @returns {void}\n */\n getMessages(page, response, error) {\n // Delegate message retrieval to the manager\n this.manager.getMessages(page, response, error);\n }\n\n /**\n * Retrieves the number of unread messages using the manager.\n * @param {Function} response - Callback to handle the count of unread messages.\n * @param {Function} error - Callback to handle any errors during retrieval.\n * @returns {void}\n */\n getNumberOfUnreadMessages(response, error) {\n // Delegate unread message count retrieval to the manager\n this.manager.getNumberOfUnreadMessages(response, error);\n }\n\n /**\n * Returns all the received data since startup.\n * @returns {Array} Array of all received data objects.\n */\n getAllReceivedData() {\n // Return received data from the manager\n return this.manager.getAllReceivedData();\n }\n\n /**\n * Marks a message as read.\n * @param {Object} message - The message to be marked as read.\n * @param {Function} response - Callback for success.\n * @param {Function} error - Callback for error.\n * @returns {void}\n */\n markMessageAsRead(message, response, error) {\n // Delegate marking message as read to the manager\n this.manager.markMessageAsRead(message, response, error);\n }\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Grovs);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs.js?"); /***/ }), /***/ "./src/grovs_api_service.js": /*!**********************************!*\ !*** ./src/grovs_api_service.js ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_api_service_helper__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_api_service_helper */ \"./src/grovs_api_service_helper.js\");\n/* harmony import */ var _grovs_context__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./grovs_context */ \"./src/grovs_context.js\");\n// Import the helper class for making API requests\n\n\n\n// Define the Grovs API service class\nclass GrovsAPIService {\n // Define endpoint paths as static properties\n static ENDPOINTS = {\n AUTHENTICATE: \"/authenticate\",\n PAYLOAD: \"/data_for_device\",\n CREATE_EVENT: \"/event\",\n CREATE_LINK: \"/create_link\",\n USER_ATTRIBUTES: \"/visitor_attributes\",\n PAYLOAD_FOR_DEVICE_AND_PATH: \"/data_for_device_and_path\",\n NOTIFICATIONS_FOR_DEVICE: \"/notifications_for_device\",\n MARK_NOTIFICATION_AS_READ: \"/mark_notification_as_read\",\n NOTIFICATIONS_TO_DISPLAY_AUTOMATICALLY:\n \"/notifications_to_display_automatically\",\n NUMBER_OF_UNREAD_MESSAGES: \"/number_of_unread_notifications\",\n };\n\n // Constructor to initialize the API service helper\n constructor() {\n this.apiService = new _grovs_api_service_helper__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n }\n\n // Method to authenticate a device\n authenticateDevice(details, response, error) {\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.AUTHENTICATE,\n details,\n response,\n error\n );\n }\n\n // Method to fetch payload for a device\n payloadForDevice(details, response, error) {\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.PAYLOAD,\n details,\n response,\n error\n );\n }\n\n // Method to fetch payload for a device and path\n payloadForDeviceAndPath(details, path, response, error) {\n const dataToSend = { ...details, path };\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.PAYLOAD_FOR_DEVICE_AND_PATH,\n dataToSend,\n response,\n error\n );\n }\n\n // Method to create an event\n createEvent(event, createdAt, path, engagementTime, response, error) {\n const data = { event };\n if (path) data.path = path;\n if (engagementTime) data.engagement_time = engagementTime;\n\n const isoDate = new Date(createdAt).toISOString();\n data.created_at = isoDate;\n\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.CREATE_EVENT,\n data,\n response,\n error\n );\n }\n\n // Method to create a link\n createLink(title, subtitle, imageUrl, data, response, error) {\n const dataToSend = {};\n if (title) dataToSend.title = title;\n if (subtitle) dataToSend.subtitle = subtitle;\n if (imageUrl) dataToSend.image_url = imageUrl;\n if (data) dataToSend.data = JSON.stringify(data);\n\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.CREATE_LINK,\n dataToSend,\n response,\n error\n );\n }\n\n // Method to set attributes\n setUserAttributes(response, error) {\n const dataToSend = {};\n dataToSend.sdk_identifier = _grovs_context__WEBPACK_IMPORTED_MODULE_1__[\"default\"].USER_IDENTIFIER;\n if (_grovs_context__WEBPACK_IMPORTED_MODULE_1__[\"default\"].USER_ATTRIBUTES) {\n dataToSend.sdk_attributes = _grovs_context__WEBPACK_IMPORTED_MODULE_1__[\"default\"].USER_ATTRIBUTES;\n }\n\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.USER_ATTRIBUTES,\n dataToSend,\n response,\n error\n );\n }\n\n messagesForDevice(page, response, error) {\n const dataToSend = { page: page };\n\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.NOTIFICATIONS_FOR_DEVICE,\n dataToSend,\n response,\n error\n );\n }\n\n markMessageAsViewed(message, response, error) {\n const dataToSend = { id: message.id };\n this.apiService.POST(\n GrovsAPIService.ENDPOINTS.MARK_NOTIFICATION_AS_READ,\n dataToSend,\n response,\n error\n );\n }\n\n messagesForAutomaticDisplay(response, error) {\n this.apiService.GET(\n GrovsAPIService.ENDPOINTS.NOTIFICATIONS_TO_DISPLAY_AUTOMATICALLY,\n null,\n response,\n error\n );\n }\n\n numberOfUnreadMessages(response, error) {\n this.apiService.GET(\n GrovsAPIService.ENDPOINTS.NUMBER_OF_UNREAD_MESSAGES,\n null,\n response,\n error\n );\n }\n}\n\n// Export the GrovsAPIService class\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsAPIService);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_api_service.js?"); /***/ }), /***/ "./src/grovs_api_service_helper.js": /*!*****************************************!*\ !*** ./src/grovs_api_service_helper.js ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_context__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_context */ \"./src/grovs_context.js\");\n\n\n/**\n * Helper class for making API requests to Grovs service.\n */\nclass GrovsAPIServiceHelper {\n // Endpoint URL for the Grovs API\n static ENDPOINT = \"https://sdk.sqd.link/api/v1/sdk\";\n // static ENDPOINT = \"http://sdk.lvh.me:3000/api/v1/sdk\";\n\n /**\n * Constructor for GrovsAPIServiceHelper.\n * @param {string} APIKey - API key for accessing the Grovs API.\n */\n constructor(APIKey) {\n this.APIKey = APIKey;\n }\n\n /**\n * Perform a POST request to the Grovs API.\n * @param {string} path - API endpoint path.\n * @param {Object} data - Data to be sent in the request body.\n * @param {Function} success - Success callback function.\n * @param {Function} error - Error callback function.\n */\n POST(path, data, success, error) {\n const headers = this.buildHeaders();\n const endpoint = GrovsAPIServiceHelper.ENDPOINT + path;\n\n const xhr = new XMLHttpRequest();\n xhr.open(\"POST\", endpoint, true);\n\n // Set request headers\n for (const key in headers) {\n xhr.setRequestHeader(key, headers[key]);\n }\n\n xhr.onreadystatechange = function () {\n if (xhr.readyState === XMLHttpRequest.DONE) {\n if (xhr.status >= 200 && xhr.status < 300) {\n const response = xhr.responseText;\n success(JSON.parse(response));\n } else {\n error(xhr.statusText);\n }\n }\n };\n\n xhr.send(JSON.stringify(data));\n }\n\n GET(path, data, success, error) {\n const headers = this.buildHeaders();\n const endpoint = GrovsAPIServiceHelper.ENDPOINT + path;\n\n const xhr = new XMLHttpRequest();\n xhr.open(\"GET\", endpoint, true);\n\n // Set request headers\n for (const key in headers) {\n xhr.setRequestHeader(key, headers[key]);\n }\n\n xhr.onreadystatechange = function () {\n if (xhr.readyState === XMLHttpRequest.DONE) {\n if (xhr.status >= 200 && xhr.status < 300) {\n const response = xhr.responseText;\n success(JSON.parse(response));\n } else {\n error(xhr.statusText);\n }\n }\n };\n\n xhr.send(JSON.stringify(data));\n }\n\n /**\n * Build request headers for the API request.\n * @returns {Object} - Request headers.\n */\n buildHeaders() {\n const headers = {};\n headers[\"Content-Type\"] = \"application/json\";\n headers[\"PLATFORM\"] = \"web\";\n\n // Get identifier\n const { protocol, hostname, port } = window.location;\n const portPart = port ? `:${port}` : \"\";\n const fullURL = `${protocol}//${hostname}${portPart}`;\n\n // Add domain identifier header\n if (window && window.location) {\n headers[\"IDENTIFIER\"] = fullURL;\n }\n\n // Add Grovs ID header\n if (_grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].linksquaredID) {\n headers[\"linksquared\"] = _grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].linksquaredID;\n }\n\n // Add API key header\n if (_grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].API_KEY) {\n if (_grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].testEnvironment) {\n headers[\"PROJECT_KEY\"] = \"test_\" + _grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].API_KEY;\n } else {\n headers[\"PROJECT_KEY\"] = _grovs_context__WEBPACK_IMPORTED_MODULE_0__[\"default\"].API_KEY;\n }\n }\n\n return headers;\n }\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsAPIServiceHelper);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_api_service_helper.js?"); /***/ }), /***/ "./src/grovs_context.js": /*!******************************!*\ !*** ./src/grovs_context.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_device_details__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_device_details */ \"./src/grovs_device_details.js\");\n// Import the GrovsDeviceDetails module\n\n\n// Define the GrovsContext class\nclass GrovsContext {\n // Static properties to store API key and Grovs ID\n /**\n * The API key used for authentication.\n * @type {string|null}\n */\n static API_KEY = null;\n\n /**\n * Indicates whether the application is running in a test environment.\n * @type {boolean}\n */\n static testEnvironment = false;\n\n static get linksquaredID() {\n return _grovs_device_details__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getValue(\"linksquared\");\n }\n\n /**\n * Set Grovs ID cookie.\n * @param {string} id - Grovs ID to be stored in the cookie.\n */\n static setLinksquaredIDCookie(id) {\n _grovs_device_details__WEBPACK_IMPORTED_MODULE_0__[\"default\"].setValue(\"linksquared\", id);\n }\n\n /**\n * Static property to store the user identifier.\n * @type {string|null}\n */\n static USER_IDENTIFIER = null;\n\n /**\n * Static property to store the user attributes.\n * @type {Object|null}\n */\n static USER_ATTRIBUTES = null;\n}\n\n// Export the GrovsContext class\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsContext);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_context.js?"); /***/ }), /***/ "./src/grovs_device_details.js": /*!*************************************!*\ !*** ./src/grovs_device_details.js ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n// Define the GrovsDeviceDetails class\nclass GrovsDeviceDetails {\n /**\n * Helper function to check if running in Electron.\n * @returns {boolean} - True if in Electron, otherwise false.\n */\n static isElectron() {\n return (\n typeof navigator !== \"undefined\" &&\n navigator.userAgent.includes(\"Electron\")\n );\n }\n\n /**\n * Get current device details.\n * @returns {Object} - Object containing user agent, app version, and build.\n */\n static currentDetails() {\n const userAgent = navigator.userAgent;\n\n // Initialize return values object\n const returnValues = {\n user_agent: userAgent,\n app_version: \"0\",\n build: \"0\",\n };\n\n return returnValues;\n }\n\n /**\n * Get the value of a cookie or local storage item by name.\n * @param {string} name - Name of the item to retrieve.\n * @returns {string|null} - Value of the item, or null if not found.\n */\n static getValue(name) {\n if (this.isElectron()) {\n return localStorage.getItem(name); // Use local storage in Electron\n } else {\n const cookies = document.cookie.split(\";\"); // Split cookies into an array\n for (let cookie of cookies) {\n const [key, value] = cookie.trim().split(\"=\"); // Split each cookie into name and value\n if (key === name) {\n return decodeURIComponent(value); // Return the decoded cookie value\n }\n }\n return null; // Return null if the item is not found\n }\n }\n\n /**\n * Removes a cookie or local storage item by name.\n * @param {string} name - Name of the item to remove.\n */\n static removeValue(name) {\n if (this.isElectron()) {\n localStorage.removeItem(name); // Remove item from local storage in Electron\n } else {\n // Set the cookie's expiration date to the past\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n }\n }\n\n /**\n * Set a cookie or local storage item with the given name and value.\n * @param {string} name - Name of the item to set.\n * @param {string} value - Value to set for the item.\n */\n static setValue(name, value) {\n if (this.isElectron()) {\n localStorage.setItem(name, value); // Set value in local storage in Electron\n } else {\n // Set expiration date to a far-future date\n const farFutureDate = new Date(\"9999-12-31\");\n const expires = \"expires=\" + farFutureDate.toUTCString();\n\n // Set the cookie\n document.cookie =\n name + \"=\" + encodeURIComponent(value) + \";\" + expires + \";path=/\";\n }\n }\n\n /**\n * Get the value of the \"Grovs\" parameter from the current URL.\n * @returns {string|null} - Value of the \"Grovs\" parameter, or null if not found.\n */\n static getGrovsPath() {\n let urlWithoutFragment = window.location.href.split(\"#\")[0];\n\n // Remove the trailing slash if it exists\n if (urlWithoutFragment.endsWith(\"/\")) {\n urlWithoutFragment = urlWithoutFragment.slice(0, -1);\n }\n\n // Create a URL object with the cleaned URL\n const url = new URL(urlWithoutFragment);\n\n // Use URLSearchParams to get the 'Grovs' parameter\n const GrovsValue = url.searchParams.get(\"Grovs\");\n\n // Decode the parameter value, if it exists\n const decodedGrovsValue = GrovsValue\n ? decodeURIComponent(GrovsValue)\n : null;\n\n if (decodedGrovsValue != null) {\n this.setValue(\"Grovs_path\", decodedGrovsValue);\n\n return decodedGrovsValue;\n } else {\n // Return it only once\n const value = this.getValue(\"Grovs_path\");\n this.removeValue(\"Grovs_path\");\n\n return value;\n }\n }\n}\n\n// Export the GrovsDeviceDetails class\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsDeviceDetails);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_device_details.js?"); /***/ }), /***/ "./src/grovs_events_manager.js": /*!*************************************!*\ !*** ./src/grovs_events_manager.js ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_api_service_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_api_service.js */ \"./src/grovs_api_service.js\");\n/* harmony import */ var _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./grovs_device_details.js */ \"./src/grovs_device_details.js\");\n// Import necessary modules\n\n\n\n/**\n * Represents an event.\n */\nclass Event {\n /**\n * Constructs an Event instance.\n * @param {string} type - The type of the event.\n * @param {number} createdAt - The timestamp when the event occurred.\n * @param {string|null} [path=null] - The path associated with the event.\n * @param {number|null} [engagementTime=null] - The engagement time for the event.\n */\n constructor(type, createdAt, path = null, engagementTime = null) {\n this.type = type; // The type of the event\n this.createdAt = createdAt; // Timestamp of when the event occurred\n this.path = path; // The associated path for the event, default is null\n this.engagementTime = engagementTime; // Engagement time for the event, default is null\n }\n}\n\n/**\n * Manages the storage of events.\n */\nclass EventsStorage {\n /**\n * Constructs an EventsStorage instance.\n * Loads events from localStorage or initializes as an empty array.\n */\n constructor() {\n this.events = JSON.parse(localStorage.getItem(\"Grovs-events\")) || [];\n }\n\n /**\n * Get all stored events.\n * @returns {Array} All stored events.\n */\n getEvents() {\n return this.events; // Return the array of stored events\n }\n\n /**\n * Store events to localStorage.\n */\n storeEventsLocally() {\n localStorage.setItem(\"Grovs-events\", JSON.stringify(this.events)); // Store events array in localStorage\n }\n\n /**\n * Store a single event.\n * @param {Event} event - The event to store.\n */\n storeEvent(event) {\n this.events.push(event); // Add the event to the events array\n this.storeEventsLocally(); // Store the updated events array in localStorage\n }\n\n /**\n * Store multiple events.\n * @param {Array<Event>} events - Array of events to store.\n */\n storeEvents(events) {\n this.events.push(...events); // Add multiple events to the events array\n this.storeEventsLocally(); // Store the updated events array in localStorage\n }\n\n /**\n * Delete an event by object reference.\n * @param {Event} eventToDelete - The event to delete.\n */\n deleteEvent(eventToDelete) {\n this.events = this.events.filter((event) => event !== eventToDelete); // Filter out the event to delete\n this.storeEventsLocally(); // Store the updated events array in localStorage\n }\n\n /**\n * Get and remove all events.\n * @returns {Array} All stored events.\n */\n getAndRemoveAllEvents() {\n const eventsToReturn = this.events; // Store current events to return\n this.events = []; // Clear the events array\n this.storeEventsLocally(); // Store the empty array in localStorage\n return eventsToReturn; // Return the stored events\n }\n\n /**\n * Set timestamp to localStorage.\n * @param {number} timestamp - The timestamp to set.\n */\n setTimestamp(timestamp) {\n localStorage.setItem(\n \"Grovs-events-timestamp\",\n JSON.stringify(timestamp) // Store the timestamp in localStorage\n );\n }\n\n /**\n * Get timestamp from localStorage.\n * @returns {number|null} The timestamp from localStorage.\n */\n getTimestamp() {\n const storedTimestamp = localStorage.getItem(\n \"Grovs-events-timestamp\" // Retrieve timestamp from localStorage\n );\n return storedTimestamp ? JSON.parse(storedTimestamp) : null; // Return parsed timestamp or null if not found\n }\n}\n\n/**\n * Manages events and their handling.\n */\nclass GrovsEventsManager {\n /**\n * Constructs a GrovsEventsManager instance.\n * Initializes Grovs API service, EventsStorage, and lastTimestamp.\n */\n constructor() {\n this.service = new _grovs_api_service_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"](); // Initialize Grovs API service\n this.eventsStorage = new EventsStorage(); // Initialize event storage\n this.lastTimestamp = Date.now(); // Set initial timestamp to current time\n\n const storedTimestamp = this.eventsStorage.getTimestamp(); // Get stored timestamp\n if (storedTimestamp) {\n this.setTimeSpent(); // Set time spent if stored timestamp exists\n this.lastTimestamp = storedTimestamp; // Update lastTimestamp to stored timestamp\n }\n\n this.eventsStorage.setTimestamp(this.lastTimestamp); // Set the current timestamp in storage\n this.handleFocus(); // Set up focus event listener\n }\n\n /**\n * Flush events to the server.\n */\n flushEvents() {\n this.flushEvents(); // Call the private flushEvents method to send events\n }\n\n /**\n * Add event.\n * @param {string} type - The type of the event.\n */\n addEvent(type) {\n const event = new Event(\n type,\n Date.now(), // Current timestamp for the event\n _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getGrovsPath(), // Path associated with the event\n null // Engagement time is initially null\n );\n this.eventsStorage.storeEvent(event); // Store the newly created event\n }\n\n /**\n * Add event and flush it to the server.\n * @param {string} type - The type of the event.\n */\n addEventWithFlush(type) {\n this.addEvent(type); // Add the event\n this.flushEvents(); // Flush events to the server\n }\n\n /**\n * Handle focus event when the window gains focus.\n * @private\n */\n handleFocus() {\n const self = this;\n window.addEventListener(\"focus\", function () {\n self.setTimeSpent(); // Update time spent when the window gains focus\n });\n }\n\n /**\n * Set time spent on the current page.\n * @private\n */\n setTimeSpent() {\n const storedTimestamp = this.eventsStorage.getTimestamp(); // Retrieve the stored timestamp\n if (storedTimestamp) {\n const currentTimestamp = Date.now(); // Current timestamp\n const differenceInMilliseconds = Math.abs(\n currentTimestamp - this.lastTimestamp // Calculate time difference\n );\n const differenceInSeconds = Math.floor(differenceInMilliseconds / 1000); // Convert to seconds\n this.setSecondsToEvents(differenceInSeconds); // Update events with the calculated seconds\n this.eventsStorage.setTimestamp(null); // Clear the stored timestamp\n }\n }\n\n /**\n * Set engagement time (in seconds) to events.\n * @param {number} seconds - The seconds to set.\n * @private\n */\n setSecondsToEvents(seconds) {\n const events = this.eventsStorage.getAndRemoveAllEvents(); // Retrieve and clear stored events\n events.forEach((event) => {\n if (event.engagementTime == null) {\n event.engagementTime = seconds; // Set engagement time if not already set\n }\n });\n this.eventsStorage.storeEvents(events); // Store the updated events back in storage\n }\n\n /**\n * Flush events to the server by sending them and deleting locally.\n * @private\n */\n flushEvents() {\n this.setPathIfNeeded(); // Update event paths if needed\n const events = this.eventsStorage.getEvents(); // Retrieve all stored events\n events.forEach((event) => {\n this.sendAndDeleteEvent(event); // Send and delete each event\n });\n }\n\n /**\n * Set the path for events if it is not already set.\n * @private\n */\n setPathIfNeeded() {\n const path = _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getGrovsPath(); // Get the current path\n if (!path) {\n return; // Exit if no path is available\n }\n const events = this.eventsStorage.getAndRemoveAllEvents(); // Retrieve and clear stored events\n events.forEach((event) => {\n if (event.path == null) {\n event.path = path; // Set path for events if not already set\n }\n });\n this.eventsStorage.storeEvents(events); // Store updated events back in storage\n }\n\n /**\n * Send the event to the server and delete it from storage.\n * @param {Event} event - The event to send and delete.\n * @private\n */\n sendAndDeleteEvent(event) {\n const self = this;\n this.service.createEvent(\n event.type,\n event.createdAt,\n event.path,\n event.engagementTime,\n (response) => {\n self.eventsStorage.deleteEvent(event); // Delete the event after successful sending\n },\n (error) => {\n // Handle error if needed\n }\n );\n }\n}\n\n// Export the GrovsEventsManager class\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsEventsManager);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_events_manager.js?"); /***/ }), /***/ "./src/grovs_manager.js": /*!******************************!*\ !*** ./src/grovs_manager.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_api_service_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_api_service.js */ \"./src/grovs_api_service.js\");\n/* harmony import */ var _grovs_events_manager_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./grovs_events_manager.js */ \"./src/grovs_events_manager.js\");\n/* harmony import */ var _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./grovs_context.js */ \"./src/grovs_context.js\");\n/* harmony import */ var _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./grovs_device_details.js */ \"./src/grovs_device_details.js\");\n/* harmony import */ var _grovs_ui_helper_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./grovs_ui_helper.js */ \"./src/grovs_ui_helper.js\");\n\n\n\n\n\n\n/**\n * Manages interactions with the Grovs API and event handling.\n */\nclass GrovsManager {\n /**\n * Creates an instance of GrovsManager.\n * @param {string} APIKey - The API key for authentication.\n * @param {boolean} testEnvironment - Indicates if the environment is a test environment.\n * @param {Function} linkHandlingCallback - Callback function to handle Grovs data.\n */\n constructor(APIKey, testEnvironment, linkHandlingCallback) {\n // Set API key and environment in the context\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].API_KEY = APIKey;\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].testEnvironment = testEnvironment;\n\n // Initialize callback for handling links\n this.linkHandlingCallback = linkHandlingCallback;\n // Initialize API service for making requests\n this.service = new _grovs_api_service_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n // Initialize event manager for handling events\n this.eventsManager = new _grovs_events_manager_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"]();\n // Authentication status\n this.authenticated = false;\n // Flag to determine if identifiers need updating\n this.shouldUpdateIdentifiers = false;\n // Initialize UI helper for UI interactions\n this.uiHelper = new _grovs_ui_helper_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"]();\n // Array to store received data\n this.receivedData = [];\n }\n\n // MARK: Methods\n\n /**\n * Authenticates with the Grovs API.\n * @param {Function} succesfullAuthenticatedCallback - Callback function invoked upon successful authentication.\n */\n authenticate(succesfullAuthenticatedCallback) {\n // Get the current device details\n let details = _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"].currentDetails();\n\n const self = this; // Preserve context for callbacks\n this.service.authenticateDevice(\n details,\n /**\n * Success callback for authentication.\n * @param {Object} response - The authentication response.\n */\n (response) => {\n // Extract relevant data from response\n let linksquaredID = response.linksquared;\n let identifier = response.sdk_identifier;\n let attributes = response.sdk_attributes;\n\n // Set Grovs ID cookie for future use\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].setLinksquaredIDCookie(linksquaredID);\n\n // Update context attributes only if identifiers are not being updated\n if (!self.shouldUpdateIdentifiers) {\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_ATTRIBUTES = identifier;\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_IDENTIFIER = attributes;\n }\n\n // Mark as authenticated\n self.authenticated = true;\n\n // Call the success callback if provided\n if (succesfullAuthenticatedCallback) {\n succesfullAuthenticatedCallback();\n }\n\n // Handle data fetching and event flushing\n self.#handleFetchData();\n self.#updateUserAttributesIfNeeded();\n self.eventsManager.flushEvents();\n },\n /**\n * Error callback for authentication.\n * @param {Object} error - The authentication error.\n */\n (error) => {\n console.log(error);\n console.log(\"Grovs - wrong credentials, the SDK will NOT work!\");\n }\n );\n }\n\n /**\n * Sets the user identifier.\n * @param {string} identifier - The user identifier.\n */\n setUserIdentifier(identifier) {\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_IDENTIFIER = identifier;\n\n // Mark for identifier update if not authenticated\n if (!this.authenticated) {\n this.shouldUpdateIdentifiers = true;\n }\n\n this.#updateUserAttributesIfNeeded();\n }\n\n /**\n * Sets the user attributes.\n * @param {Object} attributes - A dictionary of user attributes.\n */\n setUserAttributes(attributes) {\n _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_ATTRIBUTES = attributes;\n\n // Mark for identifier update if not authenticated\n if (!this.authenticated) {\n this.shouldUpdateIdentifiers = true;\n }\n\n this.#updateUserAttributesIfNeeded();\n }\n\n /**\n * Retrieves the user identifier from the GrovsContext.\n * @returns {string|null} The user identifier. Null if not authenticated.\n */\n userIdentifier() {\n return _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_IDENTIFIER;\n }\n\n /**\n * Retrieves the user attributes from the GrovsContext.\n * @returns {Object|null} The user attributes. Null if not authenticated.\n */\n userAttributes() {\n return _grovs_context_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"].USER_ATTRIBUTES;\n }\n\n /**\n * Creates a link with the Grovs API.\n * @param {string} title - The title of the link.\n * @param {string} subtitle - The subtitle of the link.\n * @param {string} imageURL - The URL of the image associated with the link.\n * @param {Object} data - Additional data for the link.\n * @param {Function} success - Success callback for creating the link.\n * @param {Function} error - Error callback for creating the link.\n */\n createLink(title, subtitle, imageURL, data, success, error) {\n // Check if authenticated before creating a link\n if (!this.authenticated) {\n error(\"The Grovs SDK is not yet initialized, try again later!\");\n }\n\n this.service.createLink(\n title,\n subtitle,\n imageURL,\n data,\n /**\n * Success callback for creating the link.\n * @param {Object} response - The response from creating the link.\n */\n (response) => {\n if (response.link) {\n success(response.link);\n return;\n }\n\n // Error handling for link creation\n error(\n \"You must configure the redirect rules in the Web interface first\"\n );\n },\n error // Error callback for the service\n );\n }\n\n /**\n * Displays the messages list using the UI helper.\n */\n showMessagesList() {\n this.uiHelper.showMessagesList();\n }\n\n /**\n * Retrieves messages for the device.\n * @param {number} page - The page number for pagination.\n * @param {Function} response - Success callback for retrieving messages.\n * @param {Function} error - Error callback for retrieving messages.\n */\n getMessages(page, response, error) {\n this.service.messagesForDevice(page, response, error);\n }\n\n /**\n * Retrieves the number of unread messages.\n * @param {Function} response - Success callback for the number of unread messages.\n * @param {Function} error - Error callback for retrieving the count.\n */\n getNumberOfUnreadMessages(response, error) {\n this.service.numberOfUnreadMessages(response, error);\n }\n\n /**\n * Returns all the received data.\n * @returns {Array} Array of all received data objects.\n */\n getAllReceivedData() {\n return this.receivedData;\n }\n\n /**\n * Marks a message as read.\n * @param {Object} message - The message to mark as read.\n * @param {Function} response - Success callback for marking the message.\n * @param {Function} error - Error callback for marking the message.\n */\n markMessageAsRead(message, response, error) {\n this.service.markMessageAsViewed(message, response, error);\n }\n\n // MARK: Private\n\n /**\n * Displays automatic messages by fetching them from the service.\n * @private\n */\n #displayAutomaticMessages() {\n this.service.messagesForAutomaticDisplay(\n (response) => {\n // Disabled for now\n // const notifications = response.notifications;\n // notifications.forEach((item) => {\n // this.uiHelper.openPage(item);\n // });\n },\n (error) => {\n console.log(\"Grovs -- could not get automatic notifications!\");\n }\n );\n }\n\n /**\n * Handles fetching data from Grovs API.\n * Determines whether to fetch data for the current device or a specific path.\n * @private\n */\n #handleFetchData() {\n const GrovsValue = _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"].getGrovsPath();\n console.log(\"Grovs - value extracted from the link\", GrovsValue);\n // Check if a specific path is set\n if (GrovsValue) {\n this.#handleGrovsValue(GrovsValue);\n } else {\n this.#handleDataForDevice();\n }\n\n // Fetch automatic messages\n this.#displayAutomaticMessages();\n }\n\n /**\n * Handles fetching data for a specific path from Grovs API.\n * @param {string} path - The path for which to fetch data.\n * @private\n */\n #handleGrovsValue(path) {\n let details = _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"].currentDetails();\n this.service.payloadForDeviceAndPath(\n details,\n path,\n /**\n * Success callback for fetching data for a specific path.\n * @param {Object} response - The response data.\n */\n (response) => {\n this.#handleDataReceived(response.data);\n },\n /**\n * Error callback for fetching data for a specific path.\n * @param {Object} error - The error object.\n */\n (error) => {\n console.log(\"Grovs -- could not fetch data!\");\n }\n );\n }\n\n /**\n * Handles fetching data for the current device from Grovs API.\n * @private\n */\n #handleDataForDevice() {\n let details = _grovs_device_details_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"].currentDetails();\n const self = this; // Preserve context for callbacks\n\n this.service.payloadForDevice(\n details,\n /**\n * Success callback for fetching data for the current device.\n * @param {Object} response - The response data.\n */\n (response) => {\n self.#handleDataReceived(response.data);\n },\n /**\n * Error callback for fetching data for the current device.\n * @param {Object} error - The error object.\n */\n (error) => {\n console.log(\"Grovs -- could not fetch data!\");\n }\n );\n }\n\n /**\n * Handles received data from Grovs API.\n * @param {Object} data - The received data.\n * @private\n */\n #handleDataReceived(data) {\n if (data) {\n // Store received data and invoke callback\n this.receivedData.push(data);\n this.linkHandlingCallback(data);\n }\n }\n\n /**\n * Updates user attributes if authenticated.\n * @private\n */\n #updateUserAttributesIfNeeded() {\n if (!this.authenticated) {\n return; // Do nothing if not authenticated\n }\n\n const self = this; // Preserve context for callbacks\n this.service.setUserAttributes(\n (response) => {\n self.shouldUpdateIdentifiers = false; // Reset update flag\n },\n /**\n * Error callback for updating user attributes.\n * @param {Object} error - The error object.\n */\n (error) => {\n console.log(\"Grovs -- could not set identifiers!\");\n }\n );\n }\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GrovsManager);\n\n\n//# sourceURL=webpack://Grovs/./src/grovs_manager.js?"); /***/ }), /***/ "./src/grovs_ui_helper.js": /*!********************************!*\ !*** ./src/grovs_ui_helper.js ***! \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _grovs_api_service__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./grovs_api_service */ \"./src/grovs_api_service.js\");\n\n\nclass GrovsUIHelper {\n constructor() {\n this.service = new _grovs_api_service__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n this.page = 1;\n this.isLoading = false;\n\n this.htmlContent = `\n <!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Messages</title>\n <link\n href=\"https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;700&display=swap\"\n rel=\"stylesheet\"\n />\n <style>\n body,\n html {\n margin: 0;\n padding: 0;\n height: 100%;\n width: 100%;\n overflow: hidden; /* Prevent scrolling when modal is open */\n\n font-family: \"Open Sans\", sans-serif; /* Use Open Sans font */\n background-color: #f0f0f0; /* Background color for contrast */\n margin: 0; /* Remove default margin */\n }\n .modal {\n display: flex;\n flex-direction: column; /* Column layout for modal content */\n left: 0;\n height: 100%; /* Full viewport height */\n backdrop-filter: blur(10px); /* Blurring effect for the background */\n color: white; /* Text color */\n z-index: 1000;\n padding: 30px; /* Padding for modal */\n padding-bottom: 0px;\n box-sizing: border-box; /* Include padding in width/height calculations */\n border-radius: 30px;\n background-color: rgba(0, 0, 0, 0.5);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); /* Shadow effect */\n }\n .modal-content {\n flex-grow: 1; /* Allow content to grow */\n border-radius: 10px; /* Rounded corners for the content box */\n position: relative; /* Relative positioning for the close button */\n overflow: hidden; /* Hide overflow */\n }\n\n #closeModalBtn {\n width: 40px;\n height: 40px;\n border: none; /* Remove border */\n background: transparent; /* Make background transparent */\n cursor: pointer; /* Change cursor on hover */\n display: flex; /* Use flexbox for centering */\n justify-content: center; /* Center the SVG horizontally */\n align-items: center; /* Center the SVG vertically */\n z-index: 1; /* Ensure button is above other content */\n padding: 0; /* Remove any padding */\n margin: 0; /* Remove any margin */\n }\n .header {\n position: sticky; /* Stick the header to the top */\n top: 0; /* Position it at the top */\n z-index: 1; /* Ensure it is above the scrolling content */\n display: flex; /* Use flexbox layout */\n justify-content: space-between; /* Space between the title and the close button */\n align-items: center; /* Center items vertically */\n height: 40px;\n margin-bottom: 20px;\n }\n .item-list {\n max-height: calc(\n 100vh - 30vh - 150px\n ); /* Adjust this value to leave space for header and button */\n overflow-y: auto; /* Enable vertical scrolling */\n }\n .item {\n display: flex; /* Flex layout for each item */\n justify-content: space-between; /* Space between title/subtitle and right arrow */\n align-items: center; /* Center vertically */\n padding: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.3); /* Separator line */\n cursor: pointer; /* Pointer cursor on hover */\n }\n .indicator {\n width: 10px; /* Width of the blue indicator */\n height: 10px; /* Height of the blue indicator */\n border-radius: 50%; /* Make it circular */\n background-color: blue; /* Blue color */\n margin-right: 10px; /* Space between indicator and title */\n }\n .right-arrow {\n margin-left: 10px; /* Space between item text and arrow */\n color: white; /* Color of the right arrow */\n }\n .title {\n font-size: 24px;\n font-weight: 600;\n padding-left: 10px;\n }\n .list-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .indicator {\n background-color: #298dfa;\n }\n .item-title {\n font-size: 17px;\n font-weight: 600;\n color: white;\n }\n .item-subtitle {\n color: rgba(255, 255, 255, 0.5);\n }\n .list-title {\n padding-left: 10px;\n }\n .spinner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 2000; /* Higher than modal */\n }\n .spinner {\n width: 40px;\n height: 40px;\n border: 4px solid rgba(255, 255, 255, 0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n @keyframes sp