-
Notifications
You must be signed in to change notification settings - Fork 34
/
index.tsx
142 lines (129 loc) · 5.23 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import React, {
createContext, FC,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
// @ts-ignore
} from 'react'
function Eventjs(){"use strict";var e={};var r=this;for(var t=0;t<arguments.length;t++){var n=arguments[t];switch(typeof n){case"string":e[n]=[];break;case"object":r=n;break;default:throw new TypeError("Eventjs() only accepts string and object parameters");break}}if(r===this&&!(this instanceof Eventjs)){throw new ReferenceError('Eventjs is not called with "new" keyword and no parameter of type object is passed to it')}function s(r){"use strict";if(typeof r!=="string"||!e[r]){throw new ReferenceError("The event name does not exist in this event manager: "+r)}return true}r.on=function(r){"use strict";s(r);for(var t=1;t<arguments.length;t++){var n=arguments[t];if(e[r].indexOf(n)===-1){e[r].push(n)}}return this};r.off=function(t){"use strict";switch(arguments.length){case 0:for(var n in e){if(e.hasOwnProperty(n)){r.off(n)}}break;case 1:s(t);e[t].length=0;break;default:s(t);for(var a=1;a<arguments.length;a++){var i=arguments[a];var o=e[t].indexOf(i);if(o!==-1){e[t].splice(o,1)}}break}return this};r.trigger=function(t){"use strict";s(t);var n=[];for(var a=1;a<arguments.length;a++){n.push(arguments[a])}var i=e[t];var o=[];for(var f=0;f<i.length;f++){var u=i[f];try{u.apply(r,n)}catch(c){o.push({listener:u,error:c})}}if(o.length>0){throw o}return this};return r}
// @ts-ignore
const events = new Eventjs( 'event' );
// @ts-ignore
import {IFlagsmith, IFlagsmithTrait, IFlagsmithFeature, IState} from '../types'
export const FlagsmithContext = createContext<IFlagsmith | null>(null)
export type FlagsmithContextType = {
flagsmith: IFlagsmith // The flagsmith instance
options?: Parameters<IFlagsmith['init']>[0] // Initialisation options, if you do not provide this you will have to call init manually
serverState?: IState
children: React.ReactElement[] | React.ReactElement;
}
export const FlagsmithProvider: FC<FlagsmithContextType> = ({
flagsmith, options, serverState, children,
}) => {
const firstRenderRef = useRef(true)
// @ts-ignore
if (serverState && !flagsmith.initialised) {
// @ts-ignore
flagsmith.setState(serverState)
}
if (firstRenderRef.current) {
firstRenderRef.current = false
if (options) {
flagsmith.init({
...options,
onChange: (...args) => {
if (options.onChange) {
options.onChange(...args)
}
events.trigger('event')
},
})
} else {
// @ts-ignore
flagsmith.trigger = ()=>events.trigger('event');
}
}
return (
<FlagsmithContext.Provider value={flagsmith}>
{children}
</FlagsmithContext.Provider>
)
}
const useConstant = function <T>(value: T): T {
const ref = useRef(value)
if (!ref.current) {
ref.current = value
}
return ref.current
}
const flagsAsArray = (_flags: any): string[] => {
if (typeof _flags === 'string') {
return [_flags]
} else if (typeof _flags === 'object') {
// eslint-disable-next-line no-prototype-builtins
if (_flags.hasOwnProperty('length')) {
return _flags
}
}
throw new Error(
'Flagsmith: please supply an array of strings or a single string of flag keys to useFlags',
)
}
const getRenderKey = (flagsmith: IFlagsmith, flags: string[], traits: string[] = []) => {
return flags
.map((k) => {
return `${flagsmith.getValue(k)}${flagsmith.hasFeature(k)}`
}).concat(traits.map((t) => (
`${flagsmith.getTrait(t)}`
)))
.join(',')
}
export function useFlags<F extends string, T extends string>(_flags: readonly F[], _traits: readonly T[] = []): {
[K in F]: IFlagsmithFeature
} & {
[K in T]: IFlagsmithTrait
} {
const flags = useConstant<string[]>(flagsAsArray(_flags))
const traits = useConstant<string[]>(flagsAsArray(_traits))
const flagsmith = useContext(FlagsmithContext)
const [renderKey, setRenderKey] = useState<string>(
getRenderKey(flagsmith, flags),
)
const renderRef = useRef<string>(renderKey)
const eventListener = useCallback(() => {
const newRenderKey = getRenderKey(flagsmith, flags, traits)
if (newRenderKey !== renderRef.current) {
renderRef.current = newRenderKey
setRenderKey(newRenderKey)
}
}, [])
useEffect(() => {
events.on('event', eventListener)
return () => {
events.off('event', eventListener)
}
}, [])
const res = useMemo(() => {
const res: any = {}
flags.map((k) => {
res[k] = {
enabled: flagsmith!.hasFeature(k),
value: flagsmith!.getValue(k),
}
}).concat(traits?.map((v) => {
res[v] = flagsmith.getTrait(v)
}))
return res
}, [renderKey])
return res
}
export const useFlagsmith = () => {
const context = useContext<IFlagsmith>(FlagsmithContext)
if (!context) {
throw new Error('useFlagsmith must be used with in a FlagsmithProvider')
}
return context as IFlagsmith
}