@stokr/components-library 2.3.65 → 2.3.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.alias = alias;
7
+ exports.hasOptedIn = hasOptedIn;
8
+ exports.identify = identify;
9
+ exports.initAnalytics = initAnalytics;
10
+ exports.optIn = optIn;
11
+ exports.optOut = optOut;
12
+ exports.reset = reset;
13
+ exports.timeEvent = timeEvent;
14
+ exports.track = track;
15
+ var _mixpanelBrowser = _interopRequireDefault(require("mixpanel-browser"));
16
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ const BLOCKED_FIELDS = new Set([
18
+ // PII
19
+ 'email', 'first_name', 'last_name', 'full_name', 'name', 'phone', 'date_of_birth', 'address', 'nationality', 'passport_number',
20
+ // Blockchain
21
+ 'wallet_address', 'tx_hash', 'transaction_hash', 'block_hash', 'contract_address', 'signing_address',
22
+ // Financial precision — server sends bucketed values only
23
+ 'amount', 'exact_amount', 'investment_amount', 'token_quantity', 'token_price', 'token_value', 'price', 'value', 'balance', 'nav', 'net_asset_value',
24
+ // Banking
25
+ 'iban', 'bic', 'swift', 'bank_account', 'routing_number',
26
+ // KYC
27
+ 'kyc_data', 'kyb_data', 'document_id', 'tax_id', 'ssn']);
28
+ const BLOCKED_PATTERNS = [/address$/i,
29
+ // wallet_address, contract_address, billing_address
30
+ /hash$/i,
31
+ // tx_hash, block_hash
32
+ /^raw_/i, /password/i, /secret/i, /private.*key/i, /\bprice\b/i, /exact/i];
33
+ function sanitize(props) {
34
+ if (!props || typeof props !== 'object' || Array.isArray(props)) {
35
+ return props !== null && props !== void 0 ? props : {};
36
+ }
37
+ const cleaned = {};
38
+ for (const [key, val] of Object.entries(props)) {
39
+ const isBlocked = BLOCKED_FIELDS.has(key.toLowerCase()) || BLOCKED_PATTERNS.some(re => re.test(key));
40
+ if (isBlocked) {
41
+ if (process.env.NODE_ENV !== 'production') {
42
+ console.warn("[analytics] Blocked field stripped before sending: \"".concat(key, "\""));
43
+ }
44
+ continue;
45
+ }
46
+ cleaned[key] = val && typeof val === 'object' && !Array.isArray(val) ? sanitize(val) : val;
47
+ }
48
+ return cleaned;
49
+ }
50
+ let initialized = false;
51
+
52
+ /**
53
+ * Call once at app root.
54
+ *
55
+ * No token → all calls are silent no-ops.
56
+ * Add `.mp-sensitive` CSS class to elements that should be masked in session recordings.
57
+ *
58
+ * @param {{ token: string, app?: string, requireConsent?: boolean }} config
59
+ * requireConsent — true only for apps with a cookie banner (e.g. homepage).
60
+ * Nothing is tracked until optIn() is called.
61
+ * Default false — authenticated apps track immediately.
62
+ */
63
+ function initAnalytics() {
64
+ let {
65
+ token,
66
+ app,
67
+ requireConsent = false
68
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
69
+ if (initialized) return;
70
+ if (!token) return;
71
+ _mixpanelBrowser.default.init(token, {
72
+ api_host: 'https://api-eu.mixpanel.com',
73
+ autocapture: {
74
+ pageview: 'full-url',
75
+ click: true,
76
+ dead_click: true,
77
+ input: true,
78
+ rage_click: true,
79
+ scroll: true,
80
+ submit: true,
81
+ capture_text_content: false // never capture visible text
82
+ },
83
+ record_sessions_percent: 100,
84
+ record_heatmap_data: true,
85
+ opt_out_tracking_by_default: requireConsent,
86
+ persistence: 'localStorage',
87
+ debug: process.env.NODE_ENV !== 'production'
88
+ });
89
+ if (app) {
90
+ _mixpanelBrowser.default.register({
91
+ app
92
+ });
93
+ }
94
+ initialized = true;
95
+ }
96
+
97
+ /** Call when user accepts the cookie/consent banner. */
98
+ function optIn() {
99
+ if (!initialized) return;
100
+ _mixpanelBrowser.default.opt_in_tracking();
101
+ }
102
+
103
+ /** Call when user declines the cookie/consent banner. */
104
+ function optOut() {
105
+ if (!initialized) return;
106
+ _mixpanelBrowser.default.opt_out_tracking();
107
+ }
108
+
109
+ /** Use to set the initial state of the cookie banner UI. */
110
+ function hasOptedIn() {
111
+ if (!initialized) return false;
112
+ return _mixpanelBrowser.default.has_opted_in_tracking();
113
+ }
114
+
115
+ /** Track a custom event. Props are sanitized before sending. */
116
+ function track(eventName) {
117
+ let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
118
+ if (!initialized) return;
119
+ _mixpanelBrowser.default.track(eventName, sanitize(props));
120
+ }
121
+
122
+ /**
123
+ * Start a duration timer. When track() is called with the same event name,
124
+ * Mixpanel automatically appends a Duration property.
125
+ *
126
+ * timeEvent('kyc.completed')
127
+ * // ... user goes through flow ...
128
+ * track('kyc.completed') // → { Duration: 142.3 }
129
+ */
130
+ function timeEvent(eventName) {
131
+ if (!initialized) return;
132
+ _mixpanelBrowser.default.time_event(eventName);
133
+ }
134
+
135
+ /**
136
+ * Called automatically by AuthContext on login — no need to call from consuming apps.
137
+ * @param {string} userId — internal UUID (_id), never email
138
+ */
139
+ function identify(userId) {
140
+ let traits = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
141
+ if (!initialized) return;
142
+ _mixpanelBrowser.default.identify(userId);
143
+ const sanitizedTraits = sanitize(traits);
144
+ if (Object.keys(sanitizedTraits).length > 0) {
145
+ _mixpanelBrowser.default.people.set(sanitizedTraits);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Only needed for legacy Mixpanel projects (Original ID Merge).
151
+ * New projects (post-2023) handle merging automatically via identify().
152
+ */
153
+ function alias(userId) {
154
+ if (!initialized) return;
155
+ _mixpanelBrowser.default.alias(userId);
156
+ }
157
+
158
+ /** Called automatically by AuthContext on logout — no need to call from consuming apps. */
159
+ function reset() {
160
+ if (!initialized) return;
161
+ _mixpanelBrowser.default.reset();
162
+ }
@@ -13,6 +13,7 @@ var _avatarPlaceholder = _interopRequireDefault(require("../static/images/avatar
13
13
  var _auth = require("firebase/auth");
14
14
  var _firebaseConfig = require("../firebase-config");
15
15
  var _fetchData = _interopRequireDefault(require("../api/fetchData"));
16
+ var _analytics = require("../analytics");
16
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
18
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
18
19
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -185,6 +186,7 @@ class AuthProviderClass extends _react.Component {
185
186
  (0, _auth.signOut)(_firebaseConfig.auth).then(() => {});
186
187
  _Auth.default.logout();
187
188
  delete _axios.default.defaults.headers.common.Authorization;
189
+ (0, _analytics.reset)();
188
190
  _this.setUser(null);
189
191
  _this.setState({
190
192
  firebaseUser: null,
@@ -250,6 +252,9 @@ class AuthProviderClass extends _react.Component {
250
252
  _this.setState({
251
253
  isFetchingUser: false
252
254
  });
255
+ (0, _analytics.identify)(user._id, {
256
+ role: user.user_type
257
+ });
253
258
 
254
259
  //redirect to home if user is on login or signup route (affects homepage only)
255
260
  _this.replaceLocationPathName();
package/dist/index.js CHANGED
@@ -1180,6 +1180,17 @@ Object.keys(_analytics).forEach(function (key) {
1180
1180
  }
1181
1181
  });
1182
1182
  });
1183
+ var _analytics2 = require("./analytics");
1184
+ Object.keys(_analytics2).forEach(function (key) {
1185
+ if (key === "default" || key === "__esModule") return;
1186
+ if (key in exports && exports[key] === _analytics2[key]) return;
1187
+ Object.defineProperty(exports, key, {
1188
+ enumerable: true,
1189
+ get: function () {
1190
+ return _analytics2[key];
1191
+ }
1192
+ });
1193
+ });
1183
1194
  var _formatCurrencyValue = require("./utils/formatCurrencyValue");
1184
1195
  Object.keys(_formatCurrencyValue).forEach(function (key) {
1185
1196
  if (key === "default" || key === "__esModule") return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stokr/components-library",
3
- "version": "2.3.65",
3
+ "version": "2.3.66",
4
4
  "description": "STOKR - Components Library",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -44,6 +44,7 @@
44
44
  "html-react-parser": "^5.0.6",
45
45
  "http-server": "^14.1.1",
46
46
  "js-cookie": "^3.0.5",
47
+ "mixpanel-browser": "^2.74.0",
47
48
  "mobile-detect": "^1.4.5",
48
49
  "moment": "^2.30.1",
49
50
  "moment-timezone": "^0.6.0",