├── App.js
├── assets
├── icon.png
└── splash.png
├── babel.config.js
├── .expo-shared
└── assets.json
├── .gitignore
├── src
├── Providers.js
├── Routes.js
├── AuthProvider.js
├── AppStack.js
└── AuthStack.js
├── app.json
└── package.json
/App.js:
--------------------------------------------------------------------------------
1 | import { Providers } from './src/Providers';
2 |
3 | export default Providers;
4 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drehimself/rn-airlock-example/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drehimself/rn-airlock-example/HEAD/assets/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "f9155ac790fd02fadcdeca367b02581c04a353aa6d5aa84409a59f6804c87acd": true,
3 | "89ed26367cdb9b771858e026f2eb95bfdb90e5ae943e716575327ec325f39c44": true
4 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
13 | # macOS
14 | .DS_Store
15 |
--------------------------------------------------------------------------------
/src/Providers.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AuthProvider } from './AuthProvider';
3 | import Routes from './Routes';
4 |
5 | export const Providers = ({}) => {
6 | return (
7 |
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Blank Template",
4 | "slug": "rn-airlock-example",
5 | "privacy": "public",
6 | "sdkVersion": "36.0.0",
7 | "platforms": [
8 | "ios",
9 | "android",
10 | "web"
11 | ],
12 | "version": "1.0.0",
13 | "orientation": "portrait",
14 | "icon": "./assets/icon.png",
15 | "splash": {
16 | "image": "./assets/splash.png",
17 | "resizeMode": "contain",
18 | "backgroundColor": "#ffffff"
19 | },
20 | "updates": {
21 | "fallbackToCacheTimeout": 0
22 | },
23 | "assetBundlePatterns": [
24 | "**/*"
25 | ],
26 | "ios": {
27 | "supportsTablet": true
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@react-native-community/masked-view": "0.1.5",
12 | "@react-navigation/native": "^5.0.9",
13 | "@react-navigation/stack": "^5.1.1",
14 | "axios": "^0.19.2",
15 | "expo": "~36.0.0",
16 | "expo-secure-store": "~8.0.0",
17 | "react": "~16.9.0",
18 | "react-dom": "~16.9.0",
19 | "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
20 | "react-native-gesture-handler": "~1.5.0",
21 | "react-native-reanimated": "~1.4.0",
22 | "react-native-safe-area-context": "0.6.0",
23 | "react-native-screens": "2.0.0-alpha.12",
24 | "react-native-web": "~0.11.7"
25 | },
26 | "devDependencies": {
27 | "@babel/core": "^7.0.0",
28 | "babel-preset-expo": "~8.0.0"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/src/Routes.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from "react";
2 | import { StyleSheet, Text, View, Button, TextInput, ActivityIndicator, AsyncStorage } from 'react-native';
3 | import { NavigationContainer } from '@react-navigation/native';
4 | import { AuthContext } from './AuthProvider';
5 | import { AuthStack } from './AuthStack';
6 | import { AppStack } from './AppStack';
7 | import * as SecureStore from 'expo-secure-store';
8 |
9 | export default function Routes() {
10 | const { user, setUser, login, logout } = useContext(AuthContext)
11 | const [loading, setLoading] = useState(true);
12 |
13 | useEffect(() => {
14 | // check if the user is logged in or not
15 | SecureStore.getItemAsync('user')
16 | .then(userString => {
17 | if (userString) {
18 | // decode it
19 | // login();
20 | userObject = JSON.parse(userString)
21 | setUser(userObject);
22 | }
23 | setLoading(false);
24 | })
25 | .catch(err => {
26 | console.log(err);
27 | })
28 | }, []);
29 |
30 | if (loading) {
31 | return (
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | return (
39 |
40 | {user ? : }
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/src/AuthProvider.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { AsyncStorage } from 'react-native';
3 | import * as SecureStore from 'expo-secure-store';
4 | import axios from 'axios';
5 |
6 | axios.defaults.baseURL = 'http://airlock-example.test';
7 |
8 | export const AuthContext = React.createContext({});
9 |
10 | export const AuthProvider = ({children}) => {
11 | const [user, setUser] = useState(null);
12 | const [error, setError] = useState(null);
13 |
14 | return (
15 | {
21 | axios.post('/api/airlock/token', {
22 | email,
23 | password,
24 | device_name: 'mobile',
25 | })
26 | .then(response => {
27 | const userResponse = {
28 | email: response.data.user.email,
29 | token: response.data.token,
30 | }
31 | setUser(userResponse);
32 | setError(null);
33 | SecureStore.setItemAsync('user', JSON.stringify(userResponse));
34 | })
35 | .catch(error => {
36 | const key = Object.keys(error.response.data.errors)[0];
37 | setError(error.response.data.errors[key][0]);
38 | })
39 | },
40 | logout: () => {
41 | axios.defaults.headers.common['Authorization'] = `Bearer ${user.token}`;
42 |
43 | axios.post('/api/logout')
44 | .then(response => {
45 | setUser(null);
46 | SecureStore.deleteItemAsync('user')
47 | })
48 | .catch(error => {
49 | console.log(error.response);
50 | })
51 | }
52 | }}>
53 | {children}
54 |
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/src/AppStack.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { useContext, useState, useEffect } from "react";
3 | import { createStackNavigator } from "@react-navigation/stack";
4 | import { AuthContext } from "./AuthProvider";
5 | import { Button, Text, View } from "react-native";
6 | import axios from 'axios';
7 |
8 | axios.defaults.baseURL = 'http://airlock-example.test';
9 |
10 | const Stack = createStackNavigator();
11 |
12 | function DashboardScreen({ navigation }) {
13 | const { user, logout } = useContext(AuthContext)
14 | const [name, setName] = useState(null);
15 |
16 | useEffect(() => {
17 | axios.defaults.headers.common['Authorization'] = `Bearer ${user.token}`;
18 |
19 | axios.get('/api/user')
20 | .then(response => {
21 | setName(response.data.name);
22 | })
23 | .catch(error => {
24 | console.log(error.response);
25 | })
26 |
27 | }, []);
28 |
29 | return (
30 |
31 | Dashboard Screen Logged In View
32 | User: {user.email}
33 | User from Server: {name}
34 |
37 | );
38 | }
39 |
40 | function SettingsScreen({ navigation }) {
41 | const { user, logout } = useContext(AuthContext)
42 |
43 | return (
44 |
45 | Settings Screen
46 | User: {user.email}
47 | navigation.navigate('Dashboard')} />
48 | logout()} />
49 |
50 | );
51 | }
52 |
53 | export const AppStack = () => {
54 | return (
55 |
56 |
57 |
58 |
59 | )
60 | }
61 |
--------------------------------------------------------------------------------
/src/AuthStack.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { useContext, useState } from "react";
3 | import { createStackNavigator } from "@react-navigation/stack";
4 | import { AuthContext } from "./AuthProvider";
5 | import { Button, Text, View, TextInput } from "react-native";
6 |
7 | const Stack = createStackNavigator();
8 |
9 | function LoginScreen({ navigation }) {
10 | const { login, error } = useContext(AuthContext);
11 | const [email, setEmail] = useState('');
12 | const [password, setPassword] = useState('');
13 |
14 | return (
15 |
16 | { error &&
17 | { error }
18 | }
19 | setEmail(text)}
22 | placeholder="Email"
23 | textContentType="emailAddress"
24 | autoCapitalize = 'none'
25 | />
26 | setPassword(text)}
29 | placeholder="Password"
30 | secureTextEntry={true}
31 | />
32 | login(email, password)}
35 | />
36 | navigation.navigate('Register')}
39 | />
40 |
41 | );
42 | }
43 |
44 | function RegisterScreen({ navigation }) {
45 | return (
46 |
47 | Register Screen
48 | navigation.navigate('Login')} />
49 | {/* navigation.goBack()} /> */}
50 |
51 | );
52 | }
53 |
54 | export const AuthStack = () => {
55 | return (
56 |
57 |
58 |
59 |
60 | )
61 | }
62 |
--------------------------------------------------------------------------------