@ninetailed/experience.js-react 2.2.9-beta.0 → 3.0.1-beta.4

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.
package/index.esm.js CHANGED
@@ -1,7 +1,8 @@
1
- import React, { createContext, useMemo, useContext, useState, useEffect, useCallback } from 'react';
1
+ import React, { createContext, useMemo, useContext, useState, useRef, useEffect, useCallback } from 'react';
2
2
  import { Ninetailed, selectVariant, selectDistribution, selectHasExperienceVariants, selectActiveExperiments, selectExperience, selectExperienceVariant } from '@ninetailed/experience.js';
3
+ import isEqual from 'lodash/isEqual';
4
+ import { logger, isBrowser } from '@ninetailed/experience.js-shared';
3
5
  import { useInView } from 'react-intersection-observer';
4
- import { isBrowser } from '@ninetailed/experience.js-shared';
5
6
  import get$1 from 'lodash/get';
6
7
  import has$1 from 'lodash/has';
7
8
 
@@ -1612,11 +1613,37 @@ $$2({ target: 'Object', stat: true, forced: Object.assign !== assign }, {
1612
1613
  const useProfile = () => {
1613
1614
  const ninetailed = useNinetailed();
1614
1615
  const [profileState, setProfileState] = useState(ninetailed.profileState);
1616
+ const profileStateRef = useRef({});
1617
+ /**
1618
+ * This effect compares the old and new profile state before updating it.
1619
+ * We use a ref to avoid an infinite loop which can happen when an empty profile state was updated with no changes.
1620
+ * This behaviour occurred as the validation handling on the error property was not set properly in the "CreateProfile" and "UpdateProfile" endpoint types.
1621
+ * Furthermore, it was also observed, that it "only" occurred when the preview plugin was used in parallel.
1622
+ */
1623
+
1615
1624
  useEffect(() => {
1616
- return ninetailed.onProfileChange(profileState => {
1617
- setProfileState(profileState);
1625
+ ninetailed.onProfileChange(profileState => {
1626
+ if (isEqual(profileState, profileStateRef.current)) {
1627
+ logger.debug("Profile State Did Not Change", profileState);
1628
+ return;
1629
+ } else {
1630
+ setProfileState(profileState);
1631
+ profileStateRef.current = profileState;
1632
+ logger.debug("Profile State Changed", profileState);
1633
+ }
1618
1634
  });
1619
1635
  }, []);
1636
+ /**
1637
+ * Old implementation without profile state deep comparison
1638
+ */
1639
+
1640
+ /*useEffect(() => {
1641
+ return ninetailed.onProfileChange((profileState) => {
1642
+ console.log('profileState', profileState);
1643
+ setProfileState(profileState);
1644
+ });
1645
+ }, []);*/
1646
+
1620
1647
  return Object.assign(Object.assign({}, profileState), {
1621
1648
  loading: profileState.status === 'loading'
1622
1649
  });
@@ -2487,16 +2514,19 @@ const useExperience = ({
2487
2514
  });
2488
2515
 
2489
2516
  if (status === 'loading') {
2517
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2490
2518
  // @ts-ignore
2491
2519
  return emptyReturn;
2492
2520
  }
2493
2521
 
2494
2522
  if (status === 'error') {
2523
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2495
2524
  // @ts-ignore
2496
2525
  return emptyReturn;
2497
2526
  }
2498
2527
 
2499
2528
  if (!profile) {
2529
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2500
2530
  // @ts-ignore
2501
2531
  return emptyReturn;
2502
2532
  }
@@ -2509,6 +2539,7 @@ const useExperience = ({
2509
2539
  });
2510
2540
 
2511
2541
  if (!experience) {
2542
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2512
2543
  // @ts-ignore
2513
2544
  return emptyReturn;
2514
2545
  }
@@ -2731,9 +2762,10 @@ const useESR = () => {
2731
2762
  const ESRLoadingComponent = _a => {
2732
2763
  var {
2733
2764
  experiences,
2734
- component: Component
2765
+ component: Component,
2766
+ passthroughProps
2735
2767
  } = _a,
2736
- baseline = __rest(_a, ["experiences", "component"]);
2768
+ baseline = __rest(_a, ["experiences", "component", "passthroughProps"]);
2737
2769
 
2738
2770
  const {
2739
2771
  experienceVariantsMap
@@ -2741,26 +2773,61 @@ const ESRLoadingComponent = _a => {
2741
2773
  const experience = experiences.find(experience => has$1(experienceVariantsMap, experience.id));
2742
2774
 
2743
2775
  if (!experience) {
2744
- return /*#__PURE__*/React.createElement(Component, Object.assign({}, baseline));
2776
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2777
+ ninetailed: {
2778
+ isPersonalized: false,
2779
+ audience: {
2780
+ id: 'baseline'
2781
+ }
2782
+ }
2783
+ }));
2745
2784
  }
2746
2785
 
2747
2786
  const component = experience.components.find(component => component.baseline.id === baseline.id);
2748
2787
 
2749
2788
  if (!component) {
2750
- return /*#__PURE__*/React.createElement(Component, Object.assign({}, baseline));
2789
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2790
+ ninetailed: {
2791
+ isPersonalized: false,
2792
+ audience: {
2793
+ id: 'baseline'
2794
+ }
2795
+ }
2796
+ }));
2751
2797
  }
2752
2798
 
2753
2799
  if (experienceVariantsMap[experience.id] === 0) {
2754
- return /*#__PURE__*/React.createElement(Component, Object.assign({}, baseline));
2800
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2801
+ ninetailed: {
2802
+ isPersonalized: false,
2803
+ audience: {
2804
+ id: 'baseline'
2805
+ }
2806
+ }
2807
+ }));
2755
2808
  }
2756
2809
 
2757
2810
  const variant = component.variants[experienceVariantsMap[experience.id] - 1];
2758
2811
 
2759
2812
  if (!variant) {
2760
- return /*#__PURE__*/React.createElement(Component, Object.assign({}, baseline));
2813
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2814
+ ninetailed: {
2815
+ isPersonalized: false,
2816
+ audience: {
2817
+ id: 'baseline'
2818
+ }
2819
+ }
2820
+ }));
2761
2821
  }
2762
2822
 
2763
- return /*#__PURE__*/React.createElement(Component, Object.assign({}, variant));
2823
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, variant, {
2824
+ ninetailed: {
2825
+ isPersonalized: false,
2826
+ audience: {
2827
+ id: 'baseline'
2828
+ }
2829
+ }
2830
+ }));
2764
2831
  };
2765
2832
 
2766
2833
  export { DefaultExperienceLoadingComponent, ESRLoadingComponent, ESRProvider, Experience, MergeTag, NinetailedProvider, Personalize, TrackHasSeenComponent, useNinetailed, usePersonalize, useProfile };
package/index.umd.js CHANGED
@@ -1,12 +1,13 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@ninetailed/experience.js'), require('react-intersection-observer'), require('@ninetailed/experience.js-shared'), require('lodash/get'), require('lodash/has')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react', '@ninetailed/experience.js', 'react-intersection-observer', '@ninetailed/experience.js-shared', 'lodash/get', 'lodash/has'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.React = {}, global.React, global.experience_js, global.reactIntersectionObserver, global.experience_jsShared, global.get$1, global.has$1));
5
- })(this, (function (exports, React, experience_js, reactIntersectionObserver, experience_jsShared, get$1, has$1) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@ninetailed/experience.js'), require('lodash/isEqual'), require('@ninetailed/experience.js-shared'), require('react-intersection-observer'), require('lodash/get'), require('lodash/has')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react', '@ninetailed/experience.js', 'lodash/isEqual', '@ninetailed/experience.js-shared', 'react-intersection-observer', 'lodash/get', 'lodash/has'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.React = {}, global.React, global.experience_js, global.isEqual, global.experience_jsShared, global.reactIntersectionObserver, global.get$1, global.has$1));
5
+ })(this, (function (exports, React, experience_js, isEqual, experience_jsShared, reactIntersectionObserver, get$1, has$1) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
+ var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
10
11
  var get__default = /*#__PURE__*/_interopDefaultLegacy(get$1);
11
12
  var has__default = /*#__PURE__*/_interopDefaultLegacy(has$1);
12
13
 
@@ -116,11 +117,37 @@
116
117
  profileState = _a[0],
117
118
  setProfileState = _a[1];
118
119
 
120
+ var profileStateRef = React.useRef({});
121
+ /**
122
+ * This effect compares the old and new profile state before updating it.
123
+ * We use a ref to avoid an infinite loop which can happen when an empty profile state was updated with no changes.
124
+ * This behaviour occurred as the validation handling on the error property was not set properly in the "CreateProfile" and "UpdateProfile" endpoint types.
125
+ * Furthermore, it was also observed, that it "only" occurred when the preview plugin was used in parallel.
126
+ */
127
+
119
128
  React.useEffect(function () {
120
- return ninetailed.onProfileChange(function (profileState) {
121
- setProfileState(profileState);
129
+ ninetailed.onProfileChange(function (profileState) {
130
+ if (isEqual__default["default"](profileState, profileStateRef.current)) {
131
+ experience_jsShared.logger.debug("Profile State Did Not Change", profileState);
132
+ return;
133
+ } else {
134
+ setProfileState(profileState);
135
+ profileStateRef.current = profileState;
136
+ experience_jsShared.logger.debug("Profile State Changed", profileState);
137
+ }
122
138
  });
123
139
  }, []);
140
+ /**
141
+ * Old implementation without profile state deep comparison
142
+ */
143
+
144
+ /*useEffect(() => {
145
+ return ninetailed.onProfileChange((profileState) => {
146
+ console.log('profileState', profileState);
147
+ setProfileState(profileState);
148
+ });
149
+ }, []);*/
150
+
124
151
  return __assign(__assign({}, profileState), {
125
152
  loading: profileState.status === 'loading'
126
153
  });
@@ -2038,16 +2065,19 @@
2038
2065
  });
2039
2066
 
2040
2067
  if (status === 'loading') {
2068
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2041
2069
  // @ts-ignore
2042
2070
  return emptyReturn;
2043
2071
  }
2044
2072
 
2045
2073
  if (status === 'error') {
2074
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2046
2075
  // @ts-ignore
2047
2076
  return emptyReturn;
2048
2077
  }
2049
2078
 
2050
2079
  if (!profile) {
2080
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2051
2081
  // @ts-ignore
2052
2082
  return emptyReturn;
2053
2083
  }
@@ -2060,6 +2090,7 @@
2060
2090
  });
2061
2091
 
2062
2092
  if (!experience) {
2093
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2063
2094
  // @ts-ignore
2064
2095
  return emptyReturn;
2065
2096
  }
@@ -2277,7 +2308,8 @@
2277
2308
  var ESRLoadingComponent = function ESRLoadingComponent(_a) {
2278
2309
  var experiences = _a.experiences,
2279
2310
  Component = _a.component,
2280
- baseline = __rest(_a, ["experiences", "component"]);
2311
+ passthroughProps = _a.passthroughProps,
2312
+ baseline = __rest(_a, ["experiences", "component", "passthroughProps"]);
2281
2313
 
2282
2314
  var experienceVariantsMap = useESR().experienceVariantsMap;
2283
2315
  var experience = experiences.find(function (experience) {
@@ -2285,7 +2317,14 @@
2285
2317
  });
2286
2318
 
2287
2319
  if (!experience) {
2288
- return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, baseline));
2320
+ return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, passthroughProps, baseline, {
2321
+ ninetailed: {
2322
+ isPersonalized: false,
2323
+ audience: {
2324
+ id: 'baseline'
2325
+ }
2326
+ }
2327
+ }));
2289
2328
  }
2290
2329
 
2291
2330
  var component = experience.components.find(function (component) {
@@ -2293,20 +2332,48 @@
2293
2332
  });
2294
2333
 
2295
2334
  if (!component) {
2296
- return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, baseline));
2335
+ return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, passthroughProps, baseline, {
2336
+ ninetailed: {
2337
+ isPersonalized: false,
2338
+ audience: {
2339
+ id: 'baseline'
2340
+ }
2341
+ }
2342
+ }));
2297
2343
  }
2298
2344
 
2299
2345
  if (experienceVariantsMap[experience.id] === 0) {
2300
- return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, baseline));
2346
+ return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, passthroughProps, baseline, {
2347
+ ninetailed: {
2348
+ isPersonalized: false,
2349
+ audience: {
2350
+ id: 'baseline'
2351
+ }
2352
+ }
2353
+ }));
2301
2354
  }
2302
2355
 
2303
2356
  var variant = component.variants[experienceVariantsMap[experience.id] - 1];
2304
2357
 
2305
2358
  if (!variant) {
2306
- return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, baseline));
2359
+ return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, passthroughProps, baseline, {
2360
+ ninetailed: {
2361
+ isPersonalized: false,
2362
+ audience: {
2363
+ id: 'baseline'
2364
+ }
2365
+ }
2366
+ }));
2307
2367
  }
2308
2368
 
2309
- return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, variant));
2369
+ return /*#__PURE__*/React__default["default"].createElement(Component, __assign({}, passthroughProps, variant, {
2370
+ ninetailed: {
2371
+ isPersonalized: false,
2372
+ audience: {
2373
+ id: 'baseline'
2374
+ }
2375
+ }
2376
+ }));
2310
2377
  };
2311
2378
 
2312
2379
  exports.DefaultExperienceLoadingComponent = DefaultExperienceLoadingComponent;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ExperienceLoadingComponent } from './Experience';
2
+ import { ExperienceBaseProps } from './Experience';
3
3
  declare type ESRContextValue = {
4
4
  experienceVariantsMap: Record<string, number>;
5
5
  };
@@ -11,5 +11,5 @@ export declare const ESRProvider: React.FC<ESRProviderProps>;
11
11
  export declare const useESR: () => {
12
12
  experienceVariantsMap: Record<string, number>;
13
13
  };
14
- export declare const ESRLoadingComponent: ExperienceLoadingComponent;
14
+ export declare const ESRLoadingComponent: <P extends Record<string, unknown>>({ experiences, component: Component, passthroughProps, ...baseline }: ExperienceBaseProps<P, Partial<P>>) => JSX.Element;
15
15
  export {};
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { AnalyticsPlugin } from 'analytics';
3
- import { OnErrorHandler, OnLogHandler, ExperienceConfiguration } from '@ninetailed/experience.js';
4
- import { Profile, Locale } from '@ninetailed/experience.js-shared';
3
+ import { ExperienceConfiguration } from '@ninetailed/experience.js';
4
+ import { Profile, Locale, OnErrorHandler, OnLogHandler } from '@ninetailed/experience.js-shared';
5
5
  export declare type NinetailedProviderProps = {
6
6
  clientId: string;
7
7
  environment?: string;
@@ -8,7 +8,39 @@ export declare const useProfile: () => {
8
8
  loading: boolean;
9
9
  from: "api" | "hydrated";
10
10
  status: "success";
11
- profile: import("@ninetailed/experience.js").Profile;
11
+ profile: {
12
+ id: string;
13
+ random: number;
14
+ audiences: string[];
15
+ traits: import("@ninetailed/experience.js-shared").Traits;
16
+ location: {
17
+ coordinates?: {
18
+ latitude: number;
19
+ longitude: number;
20
+ } | undefined;
21
+ city?: string | undefined;
22
+ postalCode?: string | undefined;
23
+ region?: string | undefined;
24
+ regionCode?: string | undefined;
25
+ country?: string | undefined;
26
+ countryCode?: string | undefined;
27
+ continent?: string | undefined;
28
+ timezone?: string | undefined;
29
+ };
30
+ session: {
31
+ isReturningVisitor: boolean;
32
+ ladingPage: {
33
+ path: string;
34
+ url: string;
35
+ query: Record<string, string>;
36
+ referrer: string;
37
+ search: string;
38
+ };
39
+ count: number;
40
+ activeSessionLength: number;
41
+ averageSessionLength: number;
42
+ };
43
+ };
12
44
  error: null;
13
45
  } | {
14
46
  loading: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js-react",
3
- "version": "2.2.9-beta.0",
3
+ "version": "3.0.1-beta.4",
4
4
  "peerDependencies": {
5
5
  "react": ">=16.8.0"
6
6
  },
@@ -8,15 +8,15 @@
8
8
  "@analytics/google-analytics": "0.5.3",
9
9
  "react-visibility-sensor": "5.1.1",
10
10
  "lodash": "^4.17.21",
11
- "@ninetailed/experience.js": "2.2.9-beta.0",
12
- "analytics": "^0.8.0",
13
- "@ninetailed/experience.js-shared": "2.2.9-beta.0",
14
- "uuid": "^8.3.2",
11
+ "@ninetailed/experience.js": "3.0.1-beta.4",
12
+ "@ninetailed/experience.js-shared": "3.0.1-beta.4",
15
13
  "ts-toolbelt": "^9.6.0",
14
+ "diary": "^0.3.1",
15
+ "zod": "^3.18.0",
16
16
  "locale-enum": "^1.1.1",
17
17
  "i18n-iso-countries": "^7.3.0",
18
+ "analytics": "^0.8.0",
18
19
  "murmurhash-js": "^1.0.0",
19
- "diary": "^0.3.1",
20
20
  "react-intersection-observer": "^8.33.1"
21
21
  },
22
22
  "main": "./index.umd.js",