@xylabs/sdk-react 2.12.8 → 2.12.9

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.
Files changed (43) hide show
  1. package/dist/cjs/common/ExperimentsHelper.d.ts +18 -0
  2. package/dist/cjs/common/ExperimentsHelper.js +101 -0
  3. package/dist/cjs/common/ExperimentsHelper.js.map +1 -0
  4. package/dist/cjs/common/index.d.ts +1 -0
  5. package/dist/cjs/common/index.js +5 -0
  6. package/dist/cjs/common/index.js.map +1 -0
  7. package/dist/cjs/components/Experiments/index.d.ts +1 -0
  8. package/dist/cjs/components/Experiments/index.js +1 -0
  9. package/dist/cjs/components/Experiments/index.js.map +1 -1
  10. package/dist/cjs/hooks/useExperiment.d.ts +8 -0
  11. package/dist/cjs/hooks/useExperiment.js +29 -0
  12. package/dist/cjs/hooks/useExperiment.js.map +1 -0
  13. package/dist/cjs/lib/Tracking/Drip/BaseEvent.js +1 -0
  14. package/dist/cjs/lib/Tracking/Drip/BaseEvent.js.map +1 -1
  15. package/dist/cjs/lib/Tracking/Tapjoy/StandardEvents.d.ts +1 -1
  16. package/dist/cjs/lib/Tracking/Tapjoy/StandardEvents.js +2 -2
  17. package/dist/cjs/lib/Tracking/Tapjoy/StandardEvents.js.map +1 -1
  18. package/dist/docs.json +15694 -15421
  19. package/dist/esm/common/ExperimentsHelper.d.ts +18 -0
  20. package/dist/esm/common/ExperimentsHelper.js +97 -0
  21. package/dist/esm/common/ExperimentsHelper.js.map +1 -0
  22. package/dist/esm/common/index.d.ts +1 -0
  23. package/dist/esm/common/index.js +2 -0
  24. package/dist/esm/common/index.js.map +1 -0
  25. package/dist/esm/components/Experiments/index.d.ts +1 -0
  26. package/dist/esm/components/Experiments/index.js +1 -0
  27. package/dist/esm/components/Experiments/index.js.map +1 -1
  28. package/dist/esm/hooks/useExperiment.d.ts +8 -0
  29. package/dist/esm/hooks/useExperiment.js +24 -0
  30. package/dist/esm/hooks/useExperiment.js.map +1 -0
  31. package/dist/esm/lib/Tracking/Drip/BaseEvent.js +1 -0
  32. package/dist/esm/lib/Tracking/Drip/BaseEvent.js.map +1 -1
  33. package/dist/esm/lib/Tracking/Tapjoy/StandardEvents.d.ts +1 -1
  34. package/dist/esm/lib/Tracking/Tapjoy/StandardEvents.js +2 -2
  35. package/dist/esm/lib/Tracking/Tapjoy/StandardEvents.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/common/ExperimentsHelper.ts +109 -0
  38. package/src/common/index.ts +1 -0
  39. package/src/components/Experiments/index.tsx +1 -0
  40. package/src/hooks/useExperiment.ts +30 -0
  41. package/src/hooks/useExperiments.stories.tsx +43 -0
  42. package/src/lib/Tracking/Drip/BaseEvent.ts +1 -0
  43. package/src/lib/Tracking/Tapjoy/StandardEvents.ts +2 -2
@@ -0,0 +1,18 @@
1
+ import { Log } from '@xylabs/sdk-js';
2
+ import { ReactElement } from 'react';
3
+ import { ExperimentProps, ExperimentsData, OutcomesData, VariantData } from '../components';
4
+ declare const ExperimentsHelper: {
5
+ buildLocalStorageKey: (localStorageProp: boolean | string) => string;
6
+ calcTotalWeight: (variants: VariantData[]) => number;
7
+ calculateExperiment: (name: string, localStorageProp: string | boolean, variants: VariantData[]) => VariantData | undefined;
8
+ getExperiment: (name: string) => import("../components").ExperimentData;
9
+ getSelectedVariant: (name: string) => VariantData | undefined;
10
+ loadOutcomes: () => OutcomesData;
11
+ makeChildrenArray: (children: ReactElement<ExperimentProps>[] | ReactElement<ExperimentProps>) => ReactElement<ExperimentProps, string | import("react").JSXElementConstructor<any>>[];
12
+ mergeData: (data: {
13
+ [index: string]: string;
14
+ }, log?: Log | undefined) => string;
15
+ saveExperimentRanges: (name: string, totalWeight: number, variants: VariantData[]) => ExperimentsData;
16
+ saveOutcomes: () => void;
17
+ };
18
+ export { ExperimentsHelper };
@@ -0,0 +1,97 @@
1
+ import { ExperimentsLocalStorageKey, OutcomesLocalStorageKey } from '../components';
2
+ import { getLocalStorageObject, setLocalStorageObject } from '../lib';
3
+ const defaultLocalStorageKey = 'testData';
4
+ const experimentsTestData = {};
5
+ let outcomes = {}; //prevent multi-outcome
6
+ // TODO - some expire logic around experiments
7
+ const ExperimentsHelper = {
8
+ buildLocalStorageKey: (localStorageProp) => {
9
+ return localStorageProp === true ? defaultLocalStorageKey : typeof localStorageProp === 'string' ? localStorageProp ?? defaultLocalStorageKey : '';
10
+ },
11
+ calcTotalWeight: (variants) => {
12
+ return variants.reduce((sum, variant) => {
13
+ return sum + variant.weight;
14
+ }, 0);
15
+ },
16
+ calculateExperiment: (name, localStorageProp, variants) => {
17
+ //TODO - user events, it needs to be in the hook, all other compatibility should
18
+ ExperimentsHelper.loadOutcomes();
19
+ const localStorageKey = ExperimentsHelper.buildLocalStorageKey(localStorageProp);
20
+ const totalWeight = ExperimentsHelper.calcTotalWeight(variants);
21
+ ExperimentsHelper.saveExperimentRanges(name, totalWeight, variants);
22
+ const firstTime = name in outcomes;
23
+ let targetWeight = outcomes[name] ?? Math.random() * totalWeight;
24
+ outcomes[name] = targetWeight;
25
+ ExperimentsHelper.saveOutcomes();
26
+ for (const variant of variants) {
27
+ targetWeight -= variant.weight;
28
+ if (targetWeight > 0)
29
+ continue;
30
+ if (!variant.name) {
31
+ throw new Error('Experiment Elements must have Keys');
32
+ }
33
+ experimentsTestData[name] = variant.name;
34
+ if (firstTime) {
35
+ localStorage.setItem(localStorageKey, ExperimentsHelper.mergeData(experimentsTestData));
36
+ }
37
+ // if (userEvents) {
38
+ // forget(userEvents.testStarted({ name, variation: variant.name }))
39
+ // }
40
+ return variant;
41
+ }
42
+ },
43
+ getExperiment: (name) => {
44
+ ExperimentsHelper.loadOutcomes();
45
+ const experiments = getLocalStorageObject(ExperimentsLocalStorageKey) || {};
46
+ return experiments[name];
47
+ },
48
+ getSelectedVariant: (name) => {
49
+ const outcomes = ExperimentsHelper.loadOutcomes();
50
+ const experiment = ExperimentsHelper.getExperiment(name);
51
+ let total = 0;
52
+ if (experiment && outcomes) {
53
+ const targetWeight = outcomes[name];
54
+ for (let i = 0; i < experiment.variants.length; i++) {
55
+ const variant = experiment.variants[i];
56
+ total += variant.weight;
57
+ if (total >= targetWeight) {
58
+ return variant;
59
+ }
60
+ }
61
+ }
62
+ },
63
+ loadOutcomes: () => {
64
+ outcomes = getLocalStorageObject(OutcomesLocalStorageKey);
65
+ return outcomes;
66
+ },
67
+ makeChildrenArray: (children) => {
68
+ if (Array.isArray(children)) {
69
+ return children;
70
+ }
71
+ else {
72
+ return [children];
73
+ }
74
+ },
75
+ mergeData: (data, log) => {
76
+ const dataArray = [];
77
+ for (const key in data) {
78
+ dataArray.push(`${key}-${data[key]}`);
79
+ }
80
+ log?.info('MergeData', dataArray.join('|'));
81
+ return dataArray.join('|');
82
+ },
83
+ saveExperimentRanges: (name, totalWeight, variants) => {
84
+ const experiments = getLocalStorageObject(ExperimentsLocalStorageKey) || {};
85
+ experiments[name] = {
86
+ totalWeight,
87
+ variants,
88
+ };
89
+ setLocalStorageObject(ExperimentsLocalStorageKey, experiments);
90
+ return experiments;
91
+ },
92
+ saveOutcomes: () => {
93
+ setLocalStorageObject(OutcomesLocalStorageKey, outcomes);
94
+ },
95
+ };
96
+ export { ExperimentsHelper };
97
+ //# sourceMappingURL=ExperimentsHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExperimentsHelper.js","sourceRoot":"","sources":["../../../src/common/ExperimentsHelper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from './ExperimentsHelper';
@@ -0,0 +1,2 @@
1
+ export * from './ExperimentsHelper';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA"}
@@ -2,3 +2,4 @@ export * from './Experiment';
2
2
  export * from './Experiments';
3
3
  export * from './ExperimentsDebugger';
4
4
  export * from './ExperimentsProps';
5
+ export * from './models';
@@ -2,4 +2,5 @@ export * from './Experiment';
2
2
  export * from './Experiments';
3
3
  export * from './ExperimentsDebugger';
4
4
  export * from './ExperimentsProps';
5
+ export * from './models';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/Experiments/index.tsx"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/Experiments/index.tsx"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,UAAU,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from 'react';
2
+ import { VariantData } from '../components';
3
+ declare const selectVariantForExperiment: (name: string, variants: Record<string, ReactNode>, defaultNode: ReactNode) => ReactNode;
4
+ declare const useExperiments: (name: string, experiments: VariantData[]) => {
5
+ experimentName: string;
6
+ selectVariant: (variants: Record<string, ReactNode>, defaultNode: ReactNode) => ReactNode;
7
+ };
8
+ export { selectVariantForExperiment, useExperiments };
@@ -0,0 +1,24 @@
1
+ import { useState } from 'react';
2
+ import { ExperimentsHelper } from '../common';
3
+ const selectVariant = (current) => (variants, defaultNode) => {
4
+ if (current && current in variants) {
5
+ return variants[current];
6
+ }
7
+ return defaultNode;
8
+ };
9
+ const selectVariantForExperiment = (name, variants, defaultNode) => {
10
+ const variant = ExperimentsHelper.getSelectedVariant(name);
11
+ if (variants[variant?.name ?? '']) {
12
+ return variants[variant?.name ?? ''];
13
+ }
14
+ return defaultNode;
15
+ };
16
+ const useExperiments = (name, experiments) => {
17
+ const [activeExperiment] = useState(ExperimentsHelper.calculateExperiment(name, true, experiments));
18
+ return {
19
+ experimentName: name,
20
+ selectVariant: selectVariant(activeExperiment?.name),
21
+ };
22
+ };
23
+ export { selectVariantForExperiment, useExperiments };
24
+ //# sourceMappingURL=useExperiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExperiment.js","sourceRoot":"","sources":["../../../src/hooks/useExperiment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAG7C,MAAM,aAAa,GAAG,CAAC,OAAgB,EAAE,EAAE,CAAC,CAAC,QAAmC,EAAE,WAAsB,EAAE,EAAE;IAC1G,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,EAAE;QAClC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;KACzB;IACD,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,0BAA0B,GAAG,CAAC,IAAY,EAAE,QAAmC,EAAE,WAAsB,EAAE,EAAE;IAC/G,MAAM,OAAO,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAC1D,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE;QACjC,OAAO,QAAQ,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA;KACrC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,WAA0B,EAAE,EAAE;IAClE,MAAM,CAAC,gBAAgB,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAA;IAEnG,OAAO;QACL,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC;KACrD,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAE,0BAA0B,EAAE,cAAc,EAAE,CAAA"}
@@ -12,6 +12,7 @@ export class DripBaseEvent {
12
12
  payload.push(this.param);
13
13
  }
14
14
  payload.push(data);
15
+ console.log('sdk-react', payload);
15
16
  this.dcq.push(payload);
16
17
  await delay(0);
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BaseEvent.js","sourceRoot":"","sources":["../../../../../src/lib/Tracking/Drip/BaseEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAItC,MAAM,OAAO,aAAa;IAKxB,YAAY,IAAY,EAAE,KAAc;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IAC1B,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAO;QACvB,MAAM,OAAO,GAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;SACzB;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACtB,MAAM,KAAK,CAAC,CAAC,CAAC,CAAA;IAChB,CAAC;IAEO,MAAM;QACZ,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAa,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAChB,MAAM,KAAK,CAAC,eAAe,CAAC,CAAA;SAC7B;QACD,OAAO,MAAM,CAAC,IAAsB,CAAA;IACtC,CAAC;IAEO,MAAM;QACZ,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAa,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAChB,MAAM,KAAK,CAAC,eAAe,CAAC,CAAA;SAC7B;QACD,OAAO,MAAM,CAAC,IAAsB,CAAA;IACtC,CAAC;CACF"}
1
+ {"version":3,"file":"BaseEvent.js","sourceRoot":"","sources":["../../../../../src/lib/Tracking/Drip/BaseEvent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAItC,MAAM,OAAO,aAAa;IAKxB,YAAY,IAAY,EAAE,KAAc;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IAC1B,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAO;QACvB,MAAM,OAAO,GAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;SACzB;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACjC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACtB,MAAM,KAAK,CAAC,CAAC,CAAC,CAAA;IAChB,CAAC;IAEO,MAAM;QACZ,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAa,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAChB,MAAM,KAAK,CAAC,eAAe,CAAC,CAAA;SAC7B;QACD,OAAO,MAAM,CAAC,IAAsB,CAAA;IACtC,CAAC;IAEO,MAAM;QACZ,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAa,CAAA;QAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAChB,MAAM,KAAK,CAAC,eAAe,CAAC,CAAA;SAC7B;QACD,OAAO,MAAM,CAAC,IAAsB,CAAA;IACtC,CAAC;CACF"}
@@ -1,5 +1,5 @@
1
1
  import { TapjoyStandardEvent } from './StandardEvent';
2
2
  declare class TapjoyStandardEvents<T extends Record<string, unknown>> {
3
- purchase(): TapjoyStandardEvent<T>;
3
+ accountCreated(): TapjoyStandardEvent<T>;
4
4
  }
5
5
  export { TapjoyStandardEvents };
@@ -1,7 +1,7 @@
1
1
  import { TapjoyStandardEvent } from './StandardEvent';
2
2
  class TapjoyStandardEvents {
3
- purchase() {
4
- return new TapjoyStandardEvent('Purchase');
3
+ accountCreated() {
4
+ return new TapjoyStandardEvent('Conversion');
5
5
  }
6
6
  }
7
7
  export { TapjoyStandardEvents };
@@ -1 +1 @@
1
- {"version":3,"file":"StandardEvents.js","sourceRoot":"","sources":["../../../../../src/lib/Tracking/Tapjoy/StandardEvents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,oBAAoB;IACjB,QAAQ;QACb,OAAO,IAAI,mBAAmB,CAAI,UAAU,CAAC,CAAA;IAC/C,CAAC;CACF;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
1
+ {"version":3,"file":"StandardEvents.js","sourceRoot":"","sources":["../../../../../src/lib/Tracking/Tapjoy/StandardEvents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,oBAAoB;IACjB,cAAc;QACnB,OAAO,IAAI,mBAAmB,CAAI,YAAY,CAAC,CAAA;IACjD,CAAC;CACF;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA"}
package/package.json CHANGED
@@ -126,6 +126,6 @@
126
126
  },
127
127
  "sideEffects": false,
128
128
  "types": "dist/esm/index.d.ts",
129
- "version": "2.12.8",
129
+ "version": "2.12.9",
130
130
  "packageManager": "yarn@3.1.1"
131
131
  }
@@ -0,0 +1,109 @@
1
+ import { Log } from '@xylabs/sdk-js'
2
+ import { ReactElement } from 'react'
3
+
4
+ import { ExperimentProps, ExperimentsData, ExperimentsLocalStorageKey, OutcomesData, OutcomesLocalStorageKey, VariantData } from '../components'
5
+ import { getLocalStorageObject, setLocalStorageObject } from '../lib'
6
+
7
+ const defaultLocalStorageKey = 'testData'
8
+ const experimentsTestData: { [index: string]: string } = {}
9
+ let outcomes: OutcomesData = {} //prevent multi-outcome
10
+
11
+ // TODO - some expire logic around experiments
12
+ const ExperimentsHelper = {
13
+ buildLocalStorageKey: (localStorageProp: boolean | string) => {
14
+ return localStorageProp === true ? defaultLocalStorageKey : typeof localStorageProp === 'string' ? localStorageProp ?? defaultLocalStorageKey : ''
15
+ },
16
+
17
+ calcTotalWeight: (variants: VariantData[]) => {
18
+ return variants.reduce((sum, variant) => {
19
+ return sum + variant.weight
20
+ }, 0)
21
+ },
22
+
23
+ calculateExperiment: (name: string, localStorageProp: string | boolean, variants: VariantData[]) => {
24
+ //TODO - user events, it needs to be in the hook, all other compatibility should
25
+ ExperimentsHelper.loadOutcomes()
26
+ const localStorageKey = ExperimentsHelper.buildLocalStorageKey(localStorageProp)
27
+ const totalWeight = ExperimentsHelper.calcTotalWeight(variants)
28
+ ExperimentsHelper.saveExperimentRanges(name, totalWeight, variants)
29
+ const firstTime = name in outcomes
30
+ let targetWeight = outcomes[name] ?? Math.random() * totalWeight
31
+ outcomes[name] = targetWeight
32
+ ExperimentsHelper.saveOutcomes()
33
+ for (const variant of variants) {
34
+ targetWeight -= variant.weight
35
+ if (targetWeight > 0) continue
36
+ if (!variant.name) {
37
+ throw new Error('Experiment Elements must have Keys')
38
+ }
39
+ experimentsTestData[name] = variant.name
40
+ if (firstTime) {
41
+ localStorage.setItem(localStorageKey, ExperimentsHelper.mergeData(experimentsTestData))
42
+ }
43
+ // if (userEvents) {
44
+ // forget(userEvents.testStarted({ name, variation: variant.name }))
45
+ // }
46
+ return variant
47
+ }
48
+ },
49
+
50
+ getExperiment: (name: string) => {
51
+ ExperimentsHelper.loadOutcomes()
52
+ const experiments = getLocalStorageObject<ExperimentsData>(ExperimentsLocalStorageKey) || {}
53
+ return experiments[name]
54
+ },
55
+
56
+ getSelectedVariant: (name: string) => {
57
+ const outcomes = ExperimentsHelper.loadOutcomes()
58
+ const experiment = ExperimentsHelper.getExperiment(name)
59
+ let total = 0
60
+ if (experiment && outcomes) {
61
+ const targetWeight = outcomes[name]
62
+ for (let i = 0; i < experiment.variants.length; i++) {
63
+ const variant = experiment.variants[i]
64
+ total += variant.weight
65
+ if (total >= targetWeight) {
66
+ return variant
67
+ }
68
+ }
69
+ }
70
+ },
71
+
72
+ loadOutcomes: () => {
73
+ outcomes = getLocalStorageObject(OutcomesLocalStorageKey)
74
+ return outcomes
75
+ },
76
+
77
+ makeChildrenArray: (children: ReactElement<ExperimentProps>[] | ReactElement<ExperimentProps>) => {
78
+ if (Array.isArray(children)) {
79
+ return children as ReactElement<ExperimentProps>[]
80
+ } else {
81
+ return [children] as ReactElement<ExperimentProps>[]
82
+ }
83
+ },
84
+
85
+ mergeData: (data: { [index: string]: string }, log?: Log) => {
86
+ const dataArray: string[] = []
87
+ for (const key in data) {
88
+ dataArray.push(`${key}-${data[key]}`)
89
+ }
90
+ log?.info('MergeData', dataArray.join('|'))
91
+ return dataArray.join('|')
92
+ },
93
+
94
+ saveExperimentRanges: (name: string, totalWeight: number, variants: VariantData[]) => {
95
+ const experiments = getLocalStorageObject<ExperimentsData>(ExperimentsLocalStorageKey) || {}
96
+ experiments[name] = {
97
+ totalWeight,
98
+ variants,
99
+ }
100
+ setLocalStorageObject(ExperimentsLocalStorageKey, experiments)
101
+ return experiments
102
+ },
103
+
104
+ saveOutcomes: () => {
105
+ setLocalStorageObject(OutcomesLocalStorageKey, outcomes)
106
+ },
107
+ }
108
+
109
+ export { ExperimentsHelper }
@@ -0,0 +1 @@
1
+ export * from './ExperimentsHelper'
@@ -2,3 +2,4 @@ export * from './Experiment'
2
2
  export * from './Experiments'
3
3
  export * from './ExperimentsDebugger'
4
4
  export * from './ExperimentsProps'
5
+ export * from './models'
@@ -0,0 +1,30 @@
1
+ import { ReactNode, useState } from 'react'
2
+
3
+ import { ExperimentsHelper } from '../common'
4
+ import { VariantData } from '../components'
5
+
6
+ const selectVariant = (current?: string) => (variants: Record<string, ReactNode>, defaultNode: ReactNode) => {
7
+ if (current && current in variants) {
8
+ return variants[current]
9
+ }
10
+ return defaultNode
11
+ }
12
+
13
+ const selectVariantForExperiment = (name: string, variants: Record<string, ReactNode>, defaultNode: ReactNode) => {
14
+ const variant = ExperimentsHelper.getSelectedVariant(name)
15
+ if (variants[variant?.name ?? '']) {
16
+ return variants[variant?.name ?? '']
17
+ }
18
+ return defaultNode
19
+ }
20
+
21
+ const useExperiments = (name: string, experiments: VariantData[]) => {
22
+ const [activeExperiment] = useState(ExperimentsHelper.calculateExperiment(name, true, experiments))
23
+
24
+ return {
25
+ experimentName: name,
26
+ selectVariant: selectVariant(activeExperiment?.name),
27
+ }
28
+ }
29
+
30
+ export { selectVariantForExperiment, useExperiments }
@@ -0,0 +1,43 @@
1
+ import { ComponentMeta, ComponentStory } from '@storybook/react'
2
+
3
+ import { selectVariantForExperiment, useExperiments } from './useExperiment'
4
+
5
+ const View: React.FC = () => {
6
+ const { experimentName, selectVariant } = useExperiments('Storybook Test', [
7
+ { name: 'a/legacy', weight: 33 },
8
+ { name: 'b/testing', weight: 33 },
9
+ { name: 'c/testing', weight: 33 },
10
+ ])
11
+ const texts = { 'a/legacy': <p>a</p>, 'b/testing': <p>b</p>, 'c/testing': <p>c</p> }
12
+ const test0 = selectVariantForExperiment('Storybook Test Does not exists', texts, <p>DefaultNode</p>)
13
+ const test1 = selectVariant({ 'a/legacy': <p>a</p>, 'b/testing': <p>b</p>, 'c/testing': <p>c</p> }, <p>default node</p>)
14
+ const test2 = selectVariantForExperiment(experimentName, texts, <p>DefaultNode</p>)
15
+ return (
16
+ <div>
17
+ <div>{test0}</div>
18
+ <div>{test1}</div>
19
+ <div>{test2}</div>
20
+ </div>
21
+ )
22
+ }
23
+
24
+ const StorybookEntry = {
25
+ argTypes: {},
26
+ component: View,
27
+ parameters: {
28
+ docs: {
29
+ page: null,
30
+ },
31
+ },
32
+ title: 'Hooks/useExperiments',
33
+ } as ComponentMeta<typeof View>
34
+
35
+ const Template: ComponentStory<typeof View> = (args) => <View {...args} />
36
+
37
+ const Default = Template.bind({})
38
+ Default.args = {}
39
+
40
+ export { Default }
41
+
42
+ // eslint-disable-next-line import/no-default-export
43
+ export default StorybookEntry
@@ -20,6 +20,7 @@ export class DripBaseEvent<T extends Record<string, unknown>> {
20
20
  payload.push(this.param)
21
21
  }
22
22
  payload.push(data)
23
+ console.log('sdk-react', payload)
23
24
  this.dcq.push(payload)
24
25
  await delay(0)
25
26
  }
@@ -1,8 +1,8 @@
1
1
  import { TapjoyStandardEvent } from './StandardEvent'
2
2
 
3
3
  class TapjoyStandardEvents<T extends Record<string, unknown>> {
4
- public purchase() {
5
- return new TapjoyStandardEvent<T>('Purchase')
4
+ public accountCreated() {
5
+ return new TapjoyStandardEvent<T>('Conversion')
6
6
  }
7
7
  }
8
8