@xylabs/sdk-react 2.8.4 → 2.9.3
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/dist/components/BasePage/BasePage.js +2 -2
- package/dist/components/BasePage/BasePage.js.map +1 -1
- package/dist/components/BasePage/BasePage.stories.js +4 -0
- package/dist/components/BasePage/BasePage.stories.js.map +1 -1
- package/dist/components/BasePage/BasePageProps.d.ts +2 -0
- package/dist/components/Experiments/Experiment.d.ts +1 -0
- package/dist/components/Experiments/Experiment.js.map +1 -1
- package/dist/components/Experiments/Experiments.d.ts +3 -8
- package/dist/components/Experiments/Experiments.js +18 -2
- package/dist/components/Experiments/Experiments.js.map +1 -1
- package/dist/components/Experiments/Experiments.stories.d.ts +6 -0
- package/dist/components/Experiments/Experiments.stories.js +27 -0
- package/dist/components/Experiments/Experiments.stories.js.map +1 -0
- package/dist/components/Experiments/ExperimentsDebugger.d.ts +3 -0
- package/dist/components/Experiments/ExperimentsDebugger.js +37 -0
- package/dist/components/Experiments/ExperimentsDebugger.js.map +1 -0
- package/dist/components/Experiments/ExperimentsDebugger.stories.d.ts +6 -0
- package/dist/components/Experiments/ExperimentsDebugger.stories.js +20 -0
- package/dist/components/Experiments/ExperimentsDebugger.stories.js.map +1 -0
- package/dist/components/Experiments/ExperimentsProps.d.ts +7 -0
- package/dist/components/Experiments/ExperimentsProps.js +2 -0
- package/dist/components/Experiments/ExperimentsProps.js.map +1 -0
- package/dist/components/Experiments/index.d.ts +2 -1
- package/dist/components/Experiments/index.js +2 -1
- package/dist/components/Experiments/index.js.map +1 -1
- package/dist/components/Experiments/models/index.d.ts +12 -0
- package/dist/components/Experiments/models/index.js +3 -0
- package/dist/components/Experiments/models/index.js.map +1 -0
- package/dist/components/dialogs/ErrorDialog.d.ts +1 -1
- package/dist/components/dialogs/ErrorDialog.js.map +1 -1
- package/dist/esm2017/components/BasePage/BasePageProps.d.ts +2 -0
- package/dist/esm2017/components/Experiments/Experiment.d.ts +1 -0
- package/dist/esm2017/components/Experiments/Experiments.d.ts +3 -8
- package/dist/esm2017/components/Experiments/Experiments.stories.d.ts +6 -0
- package/dist/esm2017/components/Experiments/ExperimentsDebugger.d.ts +3 -0
- package/dist/esm2017/components/Experiments/ExperimentsDebugger.stories.d.ts +6 -0
- package/dist/esm2017/components/Experiments/ExperimentsProps.d.ts +7 -0
- package/dist/esm2017/components/Experiments/index.d.ts +2 -1
- package/dist/esm2017/components/Experiments/models/index.d.ts +12 -0
- package/dist/esm2017/components/dialogs/ErrorDialog.d.ts +1 -1
- package/dist/esm2017/hooks/index.d.ts +1 -0
- package/dist/esm2017/hooks/useLocalStorage.d.ts +1 -0
- package/dist/esm2017/index.js +84 -6
- package/dist/esm2017/index.js.map +1 -1
- package/dist/esm5/components/BasePage/BasePageProps.d.ts +2 -0
- package/dist/esm5/components/Experiments/Experiment.d.ts +1 -0
- package/dist/esm5/components/Experiments/Experiments.d.ts +3 -8
- package/dist/esm5/components/Experiments/Experiments.stories.d.ts +6 -0
- package/dist/esm5/components/Experiments/ExperimentsDebugger.d.ts +3 -0
- package/dist/esm5/components/Experiments/ExperimentsDebugger.stories.d.ts +6 -0
- package/dist/esm5/components/Experiments/ExperimentsProps.d.ts +7 -0
- package/dist/esm5/components/Experiments/index.d.ts +2 -1
- package/dist/esm5/components/Experiments/models/index.d.ts +12 -0
- package/dist/esm5/components/dialogs/ErrorDialog.d.ts +1 -1
- package/dist/esm5/hooks/index.d.ts +1 -0
- package/dist/esm5/hooks/useLocalStorage.d.ts +1 -0
- package/dist/esm5/index.js +84 -6
- package/dist/esm5/index.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useLocalStorage.d.ts +1 -0
- package/dist/hooks/useLocalStorage.js +23 -0
- package/dist/hooks/useLocalStorage.js.map +1 -0
- package/dist/node/components/BasePage/BasePageProps.d.ts +2 -0
- package/dist/node/components/Experiments/Experiment.d.ts +1 -0
- package/dist/node/components/Experiments/Experiments.d.ts +3 -8
- package/dist/node/components/Experiments/Experiments.stories.d.ts +6 -0
- package/dist/node/components/Experiments/ExperimentsDebugger.d.ts +3 -0
- package/dist/node/components/Experiments/ExperimentsDebugger.stories.d.ts +6 -0
- package/dist/node/components/Experiments/ExperimentsProps.d.ts +7 -0
- package/dist/node/components/Experiments/index.d.ts +2 -1
- package/dist/node/components/Experiments/models/index.d.ts +12 -0
- package/dist/node/components/dialogs/ErrorDialog.d.ts +1 -1
- package/dist/node/hooks/index.d.ts +1 -0
- package/dist/node/hooks/useLocalStorage.d.ts +1 -0
- package/dist/node/index.js +84 -4
- package/dist/node/index.js.map +1 -1
- package/dist/node-esm/components/BasePage/BasePageProps.d.ts +2 -0
- package/dist/node-esm/components/Experiments/Experiment.d.ts +1 -0
- package/dist/node-esm/components/Experiments/Experiments.d.ts +3 -8
- package/dist/node-esm/components/Experiments/Experiments.stories.d.ts +6 -0
- package/dist/node-esm/components/Experiments/ExperimentsDebugger.d.ts +3 -0
- package/dist/node-esm/components/Experiments/ExperimentsDebugger.stories.d.ts +6 -0
- package/dist/node-esm/components/Experiments/ExperimentsProps.d.ts +7 -0
- package/dist/node-esm/components/Experiments/index.d.ts +2 -1
- package/dist/node-esm/components/Experiments/models/index.d.ts +12 -0
- package/dist/node-esm/components/dialogs/ErrorDialog.d.ts +1 -1
- package/dist/node-esm/hooks/index.d.ts +1 -0
- package/dist/node-esm/hooks/useLocalStorage.d.ts +1 -0
- package/dist/node-esm/index.js +84 -6
- package/dist/node-esm/index.js.map +1 -1
- package/package.json +12 -13
- package/src/components/BasePage/BasePage.stories.tsx +5 -0
- package/src/components/BasePage/BasePage.tsx +3 -0
- package/src/components/BasePage/BasePageProps.ts +2 -0
- package/src/components/Experiments/Experiment.tsx +1 -0
- package/src/components/Experiments/Experiments.stories.tsx +35 -0
- package/src/components/Experiments/Experiments.tsx +21 -10
- package/src/components/Experiments/ExperimentsDebugger.stories.tsx +24 -0
- package/src/components/Experiments/ExperimentsDebugger.tsx +71 -0
- package/src/components/Experiments/ExperimentsProps.ts +9 -0
- package/src/components/Experiments/index.tsx +2 -1
- package/src/components/Experiments/models/index.ts +8 -0
- package/src/components/dialogs/ErrorDialog.tsx +0 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useLocalStorage.ts +24 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import { Experiment } from './Experiment'
|
|
4
|
+
import { Experiments } from './Experiments'
|
|
5
|
+
|
|
6
|
+
const StorybookEntry = {
|
|
7
|
+
argTypes: {},
|
|
8
|
+
component: Experiments,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
page: null,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
title: 'Components/Experiments',
|
|
15
|
+
} as ComponentMeta<typeof Experiments>
|
|
16
|
+
|
|
17
|
+
const Template: ComponentStory<typeof Experiments> = (args) => <Experiments {...args}></Experiments>
|
|
18
|
+
|
|
19
|
+
const Default = Template.bind({})
|
|
20
|
+
Default.args = {
|
|
21
|
+
children: [
|
|
22
|
+
<Experiment weight={50} key={'true'}>
|
|
23
|
+
True
|
|
24
|
+
</Experiment>,
|
|
25
|
+
<Experiment weight={50} key={'false'}>
|
|
26
|
+
False
|
|
27
|
+
</Experiment>,
|
|
28
|
+
],
|
|
29
|
+
name: 'StorybookAB',
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { Default }
|
|
33
|
+
|
|
34
|
+
// eslint-disable-next-line import/no-default-export
|
|
35
|
+
export default StorybookEntry
|
|
@@ -4,18 +4,20 @@ import React, { ReactElement, useContext } from 'react'
|
|
|
4
4
|
import { UserEventsContext } from '../../contexts'
|
|
5
5
|
import { getLocalStorageObject, setLocalStorageObject } from '../../lib'
|
|
6
6
|
import { ExperimentProps } from './Experiment'
|
|
7
|
+
import { ExperimentsProps } from './ExperimentsProps'
|
|
8
|
+
import { ExperimentsData, ExperimentsLocalStorageKey, OutcomesData, OutcomesLocalStorageKey } from './models'
|
|
7
9
|
|
|
8
10
|
const defaultLocalStorageKey = 'testData'
|
|
9
11
|
|
|
10
12
|
const experimentsTestData: { [index: string]: string } = {}
|
|
11
|
-
let outcomes:
|
|
13
|
+
let outcomes: OutcomesData = {} //prevent multi-outcome
|
|
12
14
|
|
|
13
15
|
const saveOutcomes = () => {
|
|
14
|
-
setLocalStorageObject(
|
|
16
|
+
setLocalStorageObject(OutcomesLocalStorageKey, outcomes)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
const loadOutcomes = () => {
|
|
18
|
-
outcomes = getLocalStorageObject(
|
|
20
|
+
outcomes = getLocalStorageObject(OutcomesLocalStorageKey)
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const mergeData = (data: { [index: string]: string }, log?: Log) => {
|
|
@@ -27,12 +29,6 @@ const mergeData = (data: { [index: string]: string }, log?: Log) => {
|
|
|
27
29
|
return dataArray.join('|')
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
type Props = {
|
|
31
|
-
children: ReactElement<ExperimentProps>[] | ReactElement<ExperimentProps>
|
|
32
|
-
localStorageProp?: string | boolean
|
|
33
|
-
name: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
32
|
const missingKeyError = new Error('Experiment Elements must have Keys')
|
|
37
33
|
|
|
38
34
|
const makeChildrenArray = (children: ReactElement<ExperimentProps>[] | ReactElement<ExperimentProps>) => {
|
|
@@ -59,7 +55,19 @@ const calcTotalWeight = (childList: ReactElement<ExperimentProps>[]) => {
|
|
|
59
55
|
return totalWeight
|
|
60
56
|
}
|
|
61
57
|
|
|
62
|
-
const
|
|
58
|
+
const saveExperimentDebugRanges = (name: string, totalWeight: number, childList: ReactElement<ExperimentProps>[]) => {
|
|
59
|
+
const experiments = getLocalStorageObject<ExperimentsData>(ExperimentsLocalStorageKey) || {}
|
|
60
|
+
experiments[name] = {
|
|
61
|
+
totalWeight,
|
|
62
|
+
variants: childList.map((child) => ({
|
|
63
|
+
name: child.key?.toString(),
|
|
64
|
+
weight: child.props.weight,
|
|
65
|
+
})),
|
|
66
|
+
}
|
|
67
|
+
setLocalStorageObject(ExperimentsLocalStorageKey, experiments)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const Experiments: React.FC<ExperimentsProps> = (props) => {
|
|
63
71
|
const { name, children, localStorageProp = true } = props
|
|
64
72
|
const userEventsContext = useContext(UserEventsContext)
|
|
65
73
|
const { userEvents } = userEventsContext
|
|
@@ -71,10 +79,13 @@ const Experiments: React.FC<Props> = (props) => {
|
|
|
71
79
|
|
|
72
80
|
const totalWeight = calcTotalWeight(childList)
|
|
73
81
|
|
|
82
|
+
saveExperimentDebugRanges(name, totalWeight, childList)
|
|
83
|
+
|
|
74
84
|
const firstTime = outcomes[name] === undefined
|
|
75
85
|
let targetWeight = outcomes[name] ?? Math.random() * totalWeight
|
|
76
86
|
outcomes[name] = targetWeight
|
|
77
87
|
saveOutcomes()
|
|
88
|
+
|
|
78
89
|
for (const child of childList) {
|
|
79
90
|
targetWeight -= child.props.weight
|
|
80
91
|
if (targetWeight > 0) continue
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import { ExperimentsDebugger } from './index'
|
|
4
|
+
|
|
5
|
+
const StorybookEntry = {
|
|
6
|
+
argTypes: {},
|
|
7
|
+
component: ExperimentsDebugger,
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
page: null,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
title: 'Components/ExperimentsDebugger',
|
|
14
|
+
} as ComponentMeta<typeof ExperimentsDebugger>
|
|
15
|
+
|
|
16
|
+
const Template: ComponentStory<typeof ExperimentsDebugger> = (args) => <ExperimentsDebugger {...args} />
|
|
17
|
+
|
|
18
|
+
const Default = Template.bind({})
|
|
19
|
+
Default.args = {}
|
|
20
|
+
|
|
21
|
+
export { Default }
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line import/no-default-export
|
|
24
|
+
export default StorybookEntry
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Slider, Typography } from '@mui/material'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { useLocalStorage } from '../../hooks'
|
|
5
|
+
import { FlexCol, FlexRow } from '../FlexBox'
|
|
6
|
+
import {
|
|
7
|
+
ExperimentsData,
|
|
8
|
+
ExperimentsLocalStorageKey,
|
|
9
|
+
OutcomesData,
|
|
10
|
+
OutcomesLocalStorageKey,
|
|
11
|
+
VariantData,
|
|
12
|
+
} from './models'
|
|
13
|
+
|
|
14
|
+
const ExperimentsDebugger: React.FC = ({ ...props }) => {
|
|
15
|
+
const [experiments] = useLocalStorage<ExperimentsData>(ExperimentsLocalStorageKey, {})
|
|
16
|
+
const [outcomes, setOutcomes] = useLocalStorage<OutcomesData>(OutcomesLocalStorageKey, {})
|
|
17
|
+
|
|
18
|
+
const sumUpVariants = (items: VariantData[]) => items.reduce((acc, curr) => acc + curr.weight, 0)
|
|
19
|
+
const experimentEntries = Object.entries(experiments)
|
|
20
|
+
|
|
21
|
+
if (!experiments || !experimentEntries.length) {
|
|
22
|
+
return (
|
|
23
|
+
<FlexCol alignItems="stretch" {...props}>
|
|
24
|
+
<Typography variant="subtitle1">No Experiments loaded</Typography>
|
|
25
|
+
<Typography variant="subtitle2">Visit a page with an experiment to load the data</Typography>
|
|
26
|
+
</FlexCol>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<FlexCol alignItems="stretch" {...props}>
|
|
32
|
+
{Object.entries(experiments).map((data) => {
|
|
33
|
+
const [name, experiment] = data
|
|
34
|
+
const outcome = (outcomes[name] || 0) as number
|
|
35
|
+
|
|
36
|
+
const marks = [
|
|
37
|
+
{ label: `${experiment.variants[0].name} | ${experiment.variants[0].weight}`, value: 0 },
|
|
38
|
+
...experiment.variants.map(({ weight }, index) => ({
|
|
39
|
+
label:
|
|
40
|
+
index === experiment.variants.length - 1 ? 'End' : `${experiment.variants[index + 1].name} | ${weight}`,
|
|
41
|
+
value: index === 0 ? weight : sumUpVariants(experiment.variants.slice(0, index + 1)),
|
|
42
|
+
})),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<FlexCol key={`experiment-${name}`} alignItems="stretch" paddingX={4} marginBottom={4} {...props}>
|
|
47
|
+
<FlexRow>
|
|
48
|
+
{name}: {outcome}
|
|
49
|
+
</FlexRow>
|
|
50
|
+
<FlexRow>
|
|
51
|
+
<Slider
|
|
52
|
+
aria-label={`Experiment ${name}`}
|
|
53
|
+
defaultValue={outcome}
|
|
54
|
+
value={outcome}
|
|
55
|
+
marks={marks}
|
|
56
|
+
onChange={(e, value) => {
|
|
57
|
+
const truncated = Number((Array.isArray(value) ? value[0] : value).toFixed(2))
|
|
58
|
+
outcomes[name] = truncated
|
|
59
|
+
// Spread operator triggers rerender
|
|
60
|
+
setOutcomes({ ...outcomes })
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
</FlexRow>
|
|
64
|
+
</FlexCol>
|
|
65
|
+
)
|
|
66
|
+
})}
|
|
67
|
+
</FlexCol>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { ExperimentsDebugger }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const OutcomesLocalStorageKey = 'outcomes'
|
|
2
|
+
export const ExperimentsLocalStorageKey = 'experiments'
|
|
3
|
+
|
|
4
|
+
export type OutcomesData = Record<string, number>
|
|
5
|
+
|
|
6
|
+
export type ExperimentsData = Record<string, ExperimentData>
|
|
7
|
+
export type ExperimentData = { totalWeight: number; variants: VariantData[] }
|
|
8
|
+
export type VariantData = { weight: number; name?: string }
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { getLocalStorageObject, setLocalStorageObject } from '../lib'
|
|
4
|
+
|
|
5
|
+
export const useLocalStorage = <T>(key: string, defaultValue: T): [T, (value: T) => void] => {
|
|
6
|
+
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
7
|
+
try {
|
|
8
|
+
const item = getLocalStorageObject<T>(key)
|
|
9
|
+
return item || defaultValue
|
|
10
|
+
} catch (ex) {
|
|
11
|
+
//Error is already logged
|
|
12
|
+
return defaultValue
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const setValue = (value: T) => {
|
|
17
|
+
console.log('setValue', value)
|
|
18
|
+
setStoredValue(value)
|
|
19
|
+
setLocalStorageObject(key, value)
|
|
20
|
+
console.log('getValue from ls', getLocalStorageObject(key))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return [storedValue, setValue]
|
|
24
|
+
}
|