@kissmyappss/react-native 0.0.0-stage → 1.0.0

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/src/index.ts ADDED
@@ -0,0 +1,88 @@
1
+ // KissMyApps analytics for React Native: sessions, installs, opens, screens and your own
2
+ // events, sent to your KissMyApps project. Pure JavaScript, so there is nothing to link.
3
+
4
+ import { AppState } from 'react-native'
5
+ import { KmaClient, SDK_VERSION } from './client'
6
+ import type { ClientOptions, Properties, Storage } from './client'
7
+ import { deviceInfo } from './device'
8
+ import { navigationTracker } from './navigation'
9
+ import type { NavigationRefLike } from './navigation'
10
+
11
+ export { KmaClient, SDK_VERSION } from './client'
12
+ export type { ClientOptions, DeviceInfo, Properties, Storage } from './client'
13
+ export type { NavigationRefLike } from './navigation'
14
+
15
+ export interface InitOptions extends ClientOptions {
16
+ /** Where the SDK keeps its IDs and offline queue, such as AsyncStorage. */
17
+ storage?: Storage
18
+ }
19
+
20
+ let client: KmaClient | null = null
21
+ // Calls made before init run once it is called.
22
+ const early: ((client: KmaClient) => void)[] = []
23
+
24
+ function call(run: (client: KmaClient) => void): void {
25
+ if (client) run(client)
26
+ else if (early.length < 100) early.push(run)
27
+ }
28
+
29
+ export const KissMyApps = {
30
+ /** Starts the SDK once, as early as possible, with the project's client key. */
31
+ init(options: InitOptions): KmaClient {
32
+ if (client) return client
33
+ const started = new KmaClient(options, {
34
+ storage: options.storage ?? null,
35
+ device: deviceInfo,
36
+ fetch: (url, init) => fetch(url, init),
37
+ sdk: `kma-react-native/${SDK_VERSION}`,
38
+ })
39
+ client = started
40
+ if (AppState.currentState !== 'background') started.foreground()
41
+ AppState.addEventListener('change', (state) => {
42
+ if (state === 'active') started.foreground()
43
+ else if (state === 'background') started.background()
44
+ })
45
+ for (const run of early.splice(0)) run(started)
46
+ return started
47
+ },
48
+ track(name: string, properties?: Properties): void {
49
+ call((kma) => kma.track(name, properties))
50
+ },
51
+ screen(name: string, properties?: Properties): void {
52
+ call((kma) => kma.screen(name, properties))
53
+ },
54
+ identify(userId: string | number, traits?: Properties): void {
55
+ call((kma) => kma.identify(userId, traits))
56
+ },
57
+ setTraits(traits: Properties): void {
58
+ call((kma) => kma.setTraits(traits))
59
+ },
60
+ reset(): void {
61
+ call((kma) => kma.reset())
62
+ },
63
+ flush(): Promise<void> {
64
+ return client?.flush() ?? Promise.resolve()
65
+ },
66
+ optOut(): void {
67
+ call((kma) => kma.optOut())
68
+ },
69
+ optIn(): void {
70
+ call((kma) => kma.optIn())
71
+ },
72
+ getAnonymousId(): string | null {
73
+ return client?.getAnonymousId() ?? null
74
+ },
75
+ getSessionId(): string | null {
76
+ return client?.getSessionId() ?? null
77
+ },
78
+ }
79
+
80
+ /**
81
+ * Screen views from React Navigation:
82
+ * `<NavigationContainer ref={ref} {...trackNavigation(ref)}>`.
83
+ */
84
+ export function trackNavigation(ref: NavigationRefLike) {
85
+ return navigationTracker(ref, (name) => KissMyApps.screen(name))
86
+ }
87
+
88
+ export default KissMyApps
@@ -0,0 +1,18 @@
1
+ // Screen views from React Navigation, without depending on it: anything with
2
+ // getCurrentRoute(), such as the ref from createNavigationContainerRef(), works.
3
+
4
+ export interface NavigationRefLike {
5
+ getCurrentRoute(): { name: string } | undefined
6
+ }
7
+
8
+ /** Handlers for NavigationContainer's onReady and onStateChange that report each new screen. */
9
+ export function navigationTracker(ref: NavigationRefLike, onScreen: (name: string) => void) {
10
+ let last: string | undefined
11
+ const report = () => {
12
+ const name = ref.getCurrentRoute()?.name
13
+ if (!name || name === last) return
14
+ last = name
15
+ onScreen(name)
16
+ }
17
+ return { onReady: report, onStateChange: report }
18
+ }