Skip to content

Commit

Permalink
Better rn samples (#84)
Browse files Browse the repository at this point in the history
* chore: add shared RN sample lib

* feat: add more samples for expo
  • Loading branch information
daniel-statsig authored Mar 22, 2024
1 parent 16b0a88 commit 769239a
Show file tree
Hide file tree
Showing 25 changed files with 897 additions and 54 deletions.
7 changes: 3 additions & 4 deletions packages/client-core/src/DataAdapterCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ export abstract class DataAdapterCore {
/**
* (Internal Use Only) - Used by \@statsig/react-native-bindings to prime the cache from AsyncStorage
*
* @param {Record<string, DataAdapterResult>} cache The values to set for _inMemoryCache
* @param {Record<string, DataAdapterResult>} cache The values to merge into _inMemoryCache
*/
__setInMemoryCache(cache: Record<string, DataAdapterResult>): void {
this._inMemoryCache = cache;
__primeInMemoryCache(cache: Record<string, DataAdapterResult>): void {
this._inMemoryCache = { ...this._inMemoryCache, ...cache };
}

protected abstract _fetchFromNetwork(
Expand All @@ -111,7 +111,6 @@ export abstract class DataAdapterCore {
user?: StatsigUser,
): Promise<DataAdapterResult | null> {
const latest = await this._fetchFromNetwork(current, user);

if (!latest) {
Log.debug('No response returned for latest value');
return null;
Expand Down
4 changes: 2 additions & 2 deletions packages/client-core/src/StatsigDataAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ type DataAdapterCommon = {
/**
* (Internal Use Only) - Used by \@statsig/react-native-bindings to prime the cache from AsyncStorage
*
* @param {Record<string, DataAdapterResult>} cache The values to set for _inMemoryCache
* @param {Record<string, DataAdapterResult>} cache The values to merge into _inMemoryCache
*/
readonly __setInMemoryCache: (
readonly __primeInMemoryCache: (
cache: Record<string, DataAdapterResult>,
) => void;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/react-bindings/src/NoopEvaluationsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const _defaultEvaluation = <T>(type: 'gate' | 'config' | 'layer') => {
};

const _noopDataAdapter: EvaluationsDataAdapter & SpecsDataAdapter = {
__setInMemoryCache: _noop,
__primeInMemoryCache: _noop,
attach: _noop,
getDataSync: () => null,
getDataAsync: () => Promise.resolve(null),
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-bindings/src/AsyncStorageWarming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ async function _loadCacheAsync(
}),
);

adapter.__setInMemoryCache(results);
adapter.__primeInMemoryCache(results);
}
43 changes: 2 additions & 41 deletions samples/expo/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,6 @@
import React from 'react';
import { SafeAreaView, StatusBar, Text } from 'react-native';

import { LogLevel } from '@statsig/client-core';
import {
StatsigProviderExpo,
useGate,
warmCachingFromAsyncStorage,
} from '@statsig/expo-bindings';
import { StatsigOnDeviceEvalClient } from '@statsig/js-on-device-eval-client';

export const DEMO_CLIENT_KEY =
'client-rfLvYGag3eyU0jYW5zcIJTQip7GXxSrhOFN69IGMjvq';

const client = new StatsigOnDeviceEvalClient(DEMO_CLIENT_KEY, {
logLevel: LogLevel.Debug,
});
const warming = warmCachingFromAsyncStorage(client);

function Content(): React.ReactNode {
const gate = useGate('a_gate', { user: { userID: 'a-user' } });

return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView
style={{
flex: 1,
}}
>
<Text testID="test-text">
a_gate: {gate.value ? 'Pass' : 'Fail'} ({gate.details.reason})
</Text>
</SafeAreaView>
</>
);
}
import { SampleListView } from 'statsig-rn-shared';

export default function App(): React.ReactNode {
return (
<StatsigProviderExpo client={client} cacheWarming={warming}>
<Content />
</StatsigProviderExpo>
);
return <SampleListView />;
}
6 changes: 3 additions & 3 deletions samples/expo/src/app/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ describe('App', () => {
test(
'renders correctly',
async () => {
const { getByTestId } = render(<App />);
const { getByText } = render(<App />);

const result = await waitFor(() => getByTestId('test-text'));
expect(result).toHaveTextContent('a_gate: Pass');
const result = await waitFor(() => getByText('Bootstrapping'));
expect(result).toBeDefined();
},
1000 * 10,
);
Expand Down
23 changes: 23 additions & 0 deletions samples/rn-shared/.babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = function (api) {
api.cache(true);

return {
presets: [
[
'@nx/react/babel',
{
runtime: 'automatic',
useBuiltIns: 'usage',
},
],
],
plugins: [],
env: {
test: {
presets: [
['module:@react-native/babel-preset', { useTransformReactJSX: true }],
],
},
},
};
};
18 changes: 18 additions & 0 deletions samples/rn-shared/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "public", ".cache", "node_modules"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
22 changes: 22 additions & 0 deletions samples/rn-shared/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module.exports = {
displayName: 'rn-shared',
preset: 'react-native',
resolver: '@nx/jest/plugins/resolver',
moduleFileExtensions: ['ts', 'js', 'html', 'tsx', 'jsx'],
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
moduleNameMapper: {
'\\.svg$': '@nx/react-native/plugins/jest/svg-mock',
},
transform: {
'^.+.(js|ts|tsx)$': [
'babel-jest',
{
configFile: __dirname + '/.babelrc.js',
},
],
'^.+.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': require.resolve(
'react-native/jest/assetFileTransformer.js',
),
},
coverageDirectory: '../../coverage/samples/rn-shared',
};
19 changes: 19 additions & 0 deletions samples/rn-shared/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "rn-shared",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "samples/rn-shared/src",
"projectType": "library",
"tags": [],
"targets": {
"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "samples/rn-shared/jest.config.ts"
}
}
}
}
2 changes: 2 additions & 0 deletions samples/rn-shared/src/Constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const DEMO_CLIENT_KEY =
'client-rfLvYGag3eyU0jYW5zcIJTQip7GXxSrhOFN69IGMjvq';
44 changes: 44 additions & 0 deletions samples/rn-shared/src/DummyAuthService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { DJB2, StatsigUser, Storage } from '@statsig/client-core';

type LoginFormData = {
email: string;
password: string;
};

type AuthResult = {
authorizedUser: StatsigUser;
};

const storageKey = 'fake_logged_in_user';

const service = {
login: async (data: LoginFormData): Promise<AuthResult> => {
await new Promise<void>((r) => setTimeout(r, 1000));
const userID = `user-${DJB2(data.email)}`;
const user = { userID, email: data.email };
await Storage.setItem(storageKey, JSON.stringify(user));

const authorizedUser = user;

return {
authorizedUser, // An authenticated StatsigUser object
};
},

getUser: async (): Promise<StatsigUser> => {
const data = await Storage.getItem(storageKey);
if (!data) {
return { userID: '' };
}

return JSON.parse(data) as StatsigUser;
},
logout: (): void => {
Storage.removeItem(storageKey).catch((e) => {
// eslint-disable-next-line no-console
console.error(e);
});
},
};

export const AuthService = service;
56 changes: 56 additions & 0 deletions samples/rn-shared/src/SampleListView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState } from 'react';
import {
FlatList,
SafeAreaView,
StatusBar,
Text,
TouchableOpacity,
} from 'react-native';

import { RNBootstrapExample } from './examples/RNBootstrapExample';
import { RNLoginExample } from './examples/RNLoginExample';

const fruits = [
{ name: 'Bootstrapping' },
{ name: 'Login Flow' },
{ name: 'Login Flo2w' },
];

export function SampleListView(): React.ReactNode {
const [selectedExample, setSelectedExample] = useState<string | null>(null);

const onBackPress = () => setSelectedExample(null);

return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={{ flex: 1 }}>
{(() => {
switch (selectedExample) {
case 'Bootstrapping':
return <RNBootstrapExample onBackPress={onBackPress} />;

case 'Login Flow':
return <RNLoginExample onBackPress={onBackPress} />;

default:
return (
<FlatList
data={fruits}
renderItem={(args) => (
<TouchableOpacity
style={{ padding: 10, borderBottomWidth: 1 }}
onPress={() => setSelectedExample(args.item.name)}
>
<Text style={{ fontSize: 18 }}>{args.item.name}</Text>
</TouchableOpacity>
)}
keyExtractor={(item) => item.name.toString()}
/>
);
}
})()}
</SafeAreaView>
</>
);
}
Loading

0 comments on commit 769239a

Please sign in to comment.