Skip to content

Commit

Permalink
feat: React Native Application using Eppo SDK (#106)
Browse files Browse the repository at this point in the history
* inital app from create-expo-app
* add Eppo SDK; traditional and precomputed client
* Eppo Client provider and basic flag/bandit display
  • Loading branch information
typotter authored Jan 20, 2025
1 parent 2eea02c commit e7e9a7b
Show file tree
Hide file tree
Showing 45 changed files with 10,346 additions and 0 deletions.
8 changes: 8 additions & 0 deletions package-testing/react-native-sdk-relay/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// https://docs.expo.dev/guides/using-eslint/
module.exports = {
extends: ['expo', 'prettier'],
plugins: ['prettier'],
rules: {
'prettier/prettier': 'error',
},
};
38 changes: 38 additions & 0 deletions package-testing/react-native-sdk-relay/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

app-example
50 changes: 50 additions & 0 deletions package-testing/react-native-sdk-relay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Welcome to your Expo app 👋

This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).

## Get started

1. Install dependencies

```bash
npm install
```

2. Start the app

```bash
npx expo start
```

In the output, you'll find options to open the app in a

- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo

You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).

## Get a fresh project

When you're ready, run:

```bash
npm run reset-project
```

This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.

## Learn more

To learn more about developing your project with Expo, look at the following resources:

- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.

## Join the community

Join our community of developers creating universal apps.

- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
41 changes: 41 additions & 0 deletions package-testing/react-native-sdk-relay/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"expo": {
"name": "react-native-sdk-relay",
"slug": "react-native-sdk-relay",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router",
[
"expo-splash-screen",
{
"image": "./assets/images/splash-icon.png",
"imageWidth": 200,
"resizeMode": "contain",
"backgroundColor": "#ffffff"
}
]
],
"experiments": {
"typedRoutes": true
}
}
}
53 changes: 53 additions & 0 deletions package-testing/react-native-sdk-relay/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { Platform } from 'react-native';

import { HapticTab } from '@/components/HapticTab';
import { IconSymbol } from '@/components/ui/IconSymbol';
import TabBarBackground from '@/components/ui/TabBarBackground';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';

export default function TabLayout() {
const colorScheme = useColorScheme();

return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
tabBarButton: HapticTab,
tabBarBackground: TabBarBackground,
tabBarStyle: Platform.select({
ios: {
// Use a transparent background on iOS to show the blur effect
position: 'absolute',
},
default: {},
}),
}}
>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
}}
/>
<Tabs.Screen
name="bandits"
options={{
title: 'Bandits',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
}}
/>
<Tabs.Screen
name="eppo-flags"
options={{
title: 'Flags',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="flag.fill" color={color} />,
}}
/>
</Tabs>
);
}
100 changes: 100 additions & 0 deletions package-testing/react-native-sdk-relay/app/(tabs)/bandits.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { StyleSheet } from 'react-native';

import { Collapsible } from '@/components/Collapsible';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { IconSymbol } from '@/components/ui/IconSymbol';
import { useEffect, useState } from 'react';
import { getInstance } from '@eppo/react-native-sdk';
import { useSubjectAttributes } from '@/hooks/useSubjectAttributes';
import { useEppoPrecomputedClient } from '@/hooks/useEppoPrecomputedClient';

export default function BanditTabScreen() {
const [updateHighlightsBanditVariation, setUpdateHighlightsBanditVariation] = useState<string>('LOADING...');
const [updateHighlightsBanditAction, setUpdateHighlightsBanditAction] = useState<string>('');

const [updateHighlightsFlagValue, setUpdateHighlightsFlagValue] = useState<string>('LOADING...');
const [precomputedFlagValue, setPrecomputedFlagValue] = useState<string>('LOADING...');

const subjectAttributes = useSubjectAttributes();
const client = useEppoPrecomputedClient();

// const client = useEppoPrecomputedClient();

useEffect(() => {
try {
const result = client.getBanditAction('update-highlights-bandit', 'NONE');

setUpdateHighlightsBanditVariation(result?.variation ?? 'ERROR');
setUpdateHighlightsBanditAction(result?.action ?? 'ERROR');

const flagResult = getInstance().getStringAssignment(
'update-highlights-bandit',
'user123',
subjectAttributes,
'NONE',
);
setUpdateHighlightsFlagValue(flagResult);

const precomputedFlagResult = client.getStringAssignment('update-highlights-bandit', 'NONE');
setPrecomputedFlagValue(precomputedFlagResult);
} catch (error) {
console.error('Error in bandit effect:', error);
setUpdateHighlightsBanditVariation('ERROR');
setUpdateHighlightsBanditAction('ERROR');
}
}, [client, subjectAttributes]);

return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={
<IconSymbol
size={310}
color="#808080"
name="chevron.left.forwardslash.chevron.right"
style={styles.headerImage}
/>
}
>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Bandits</ThemedText>
</ThemedView>
<ThemedText>Here we are seeing the first bandits on a mobile app!</ThemedText>
<Collapsible title="update-highlights-bandit">
<ThemedText>
<ThemedText type="defaultSemiBold">VariationValue</ThemedText>{' '}
<ThemedText>{updateHighlightsBanditVariation}</ThemedText>
</ThemedText>
<ThemedText>
<ThemedText type="defaultSemiBold">Bandit Value</ThemedText>{' '}
<ThemedText>{updateHighlightsBanditAction}</ThemedText>
</ThemedText>
</Collapsible>
<Collapsible title="update-highlights-bandit Flag Value">
<ThemedText>
<ThemedText type="defaultSemiBold">Traditional Client</ThemedText>{' '}
<ThemedText>{updateHighlightsFlagValue}</ThemedText>
</ThemedText>
<ThemedText>
<ThemedText type="defaultSemiBold">Precomputed Client</ThemedText>{' '}
<ThemedText>{precomputedFlagValue}</ThemedText>
</ThemedText>
</Collapsible>
</ParallaxScrollView>
);
}

const styles = StyleSheet.create({
headerImage: {
color: '#808080',
bottom: -90,
left: -35,
position: 'absolute',
},
titleContainer: {
flexDirection: 'row',
gap: 8,
},
});
62 changes: 62 additions & 0 deletions package-testing/react-native-sdk-relay/app/(tabs)/eppo-flags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { StyleSheet, Image, Platform } from 'react-native';

import { Collapsible } from '@/components/Collapsible';
import { ExternalLink } from '@/components/ExternalLink';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { IconSymbol } from '@/components/ui/IconSymbol';
import React from 'react';
import { TypeCompiler } from '@sinclair/typebox/compiler';
import Code = TypeCompiler.Code;
import EppoFlagKeyDump from '@/components/EppoFlagKeyDump';

export default function EppoFlagsScreen() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={
<IconSymbol
size={310}
color="#808080"
name="chevron.left.forwardslash.chevron.right"
style={styles.headerImage}
/>
}
>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Eppo Flag Assignments</ThemedText>
</ThemedView>
<ThemedText>Get dynamic values for your app based on your Eppo Experiments and Feature Flags.</ThemedText>
<Collapsible title="Assignment Methods">
<ThemedText>
<ThemedText>
getBooleanAssignment(...) getNumericAssignment(...) getIntegerAssignment(...) getStringAssignment(...)
getJSONAssignment(...)
</ThemedText>
</ThemedText>
<ExternalLink href="https://docs.geteppo.com/sdks/client-sdks/react-native/" target="_blank">
<ThemedText type="link">Learn more</ThemedText>
</ExternalLink>
</Collapsible>
<Collapsible title="Flag Keys">
<ThemedText>These flags have been loaded by the traditional Eppo SDK.</ThemedText>
<ThemedText type="defaultSemiBold">They are probably hashed.</ThemedText>
<EppoFlagKeyDump></EppoFlagKeyDump>
</Collapsible>
</ParallaxScrollView>
);
}

const styles = StyleSheet.create({
headerImage: {
color: '#808080',
bottom: -90,
left: -35,
position: 'absolute',
},
titleContainer: {
flexDirection: 'row',
gap: 8,
},
});
Loading

0 comments on commit e7e9a7b

Please sign in to comment.