Skip to content

Commit d58e149

Browse files
committed
docs: add example app
1 parent 3b9bc09 commit d58e149

17 files changed

+694
-216
lines changed

.github/workflows/ci.yml

+13
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,16 @@ jobs:
4646

4747
- name: Build package
4848
run: yarn prepack
49+
50+
build-web:
51+
runs-on: ubuntu-latest
52+
steps:
53+
- name: Checkout
54+
uses: actions/checkout@v3
55+
56+
- name: Setup
57+
uses: ./.github/actions/setup
58+
59+
- name: Build example for Web
60+
run: |
61+
yarn example expo export:web

example/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web-build

example/App.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './src/App';

example/app.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"expo": {
3+
"name": "react-native-laravel-sanctum-example",
4+
"slug": "react-native-laravel-sanctum-example",
5+
"version": "1.0.0",
6+
"orientation": "portrait",
7+
"icon": "./assets/icon.png",
8+
"userInterfaceStyle": "light",
9+
"splash": {
10+
"image": "./assets/splash.png",
11+
"resizeMode": "contain",
12+
"backgroundColor": "#ffffff"
13+
},
14+
"assetBundlePatterns": [
15+
"**/*"
16+
],
17+
"ios": {
18+
"supportsTablet": true
19+
},
20+
"android": {
21+
"adaptiveIcon": {
22+
"foregroundImage": "./assets/adaptive-icon.png",
23+
"backgroundColor": "#ffffff"
24+
}
25+
},
26+
"web": {
27+
"favicon": "./assets/favicon.png"
28+
}
29+
}
30+
}

example/assets/adaptive-icon.png

17.1 KB
Loading

example/assets/favicon.png

1.43 KB
Loading

example/assets/icon.png

21.9 KB
Loading

example/assets/splash.png

46.2 KB
Loading

example/babel.config.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const path = require('path');
2+
const pak = require('../package.json');
3+
4+
module.exports = function (api) {
5+
api.cache(true);
6+
7+
return {
8+
presets: ['babel-preset-expo'],
9+
plugins: [
10+
[
11+
'module-resolver',
12+
{
13+
extensions: ['.tsx', '.ts', '.js', '.json'],
14+
alias: {
15+
// For development, we want to alias the library to the source
16+
[pak.name]: path.join(__dirname, '..', pak.source),
17+
},
18+
},
19+
],
20+
],
21+
};
22+
};

example/metro.config.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const path = require('path');
2+
const escape = require('escape-string-regexp');
3+
const { getDefaultConfig } = require('@expo/metro-config');
4+
const exclusionList = require('metro-config/src/defaults/exclusionList');
5+
const pak = require('../package.json');
6+
7+
const root = path.resolve(__dirname, '..');
8+
const modules = Object.keys({ ...pak.peerDependencies });
9+
10+
const defaultConfig = getDefaultConfig(__dirname);
11+
12+
/**
13+
* Metro configuration
14+
* https://facebook.github.io/metro/docs/configuration
15+
*
16+
* @type {import('metro-config').MetroConfig}
17+
*/
18+
const config = {
19+
...defaultConfig,
20+
21+
projectRoot: __dirname,
22+
watchFolders: [root],
23+
24+
// We need to make sure that only one version is loaded for peerDependencies
25+
// So we block them at the root, and alias them to the versions in example's node_modules
26+
resolver: {
27+
...defaultConfig.resolver,
28+
29+
blacklistRE: exclusionList(
30+
modules.map(
31+
(m) =>
32+
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
33+
)
34+
),
35+
36+
extraNodeModules: modules.reduce((acc, name) => {
37+
acc[name] = path.join(__dirname, 'node_modules', name);
38+
return acc;
39+
}, {}),
40+
},
41+
};
42+
43+
module.exports = config;

example/package.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "example",
3+
"version": "1.0.0",
4+
"main": "node_modules/expo/AppEntry.js",
5+
"scripts": {
6+
"start": "expo start",
7+
"android": "expo start --android",
8+
"ios": "expo start --ios",
9+
"web": "expo start --web"
10+
},
11+
"dependencies": {
12+
"expo": "~49.0.7",
13+
"expo-secure-store": "~12.3.1",
14+
"expo-status-bar": "~1.6.0",
15+
"react": "18.2.0",
16+
"react-dom": "18.2.0",
17+
"react-native": "0.72.4",
18+
"react-native-laravel-sanctum": "file:react-native-laravel-sanctum-0.2.0.tgz",
19+
"react-native-web": "~0.19.6"
20+
},
21+
"devDependencies": {
22+
"@babel/core": "^7.20.0",
23+
"@expo/webpack-config": "^19.0.0",
24+
"babel-loader": "^8.1.0",
25+
"babel-plugin-module-resolver": "^5.0.0"
26+
},
27+
"private": true
28+
}

example/src/App.tsx

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
3+
import { AuthProvider, useAuth } from 'react-native-laravel-sanctum';
4+
5+
function Login() {
6+
const {
7+
login,
8+
getToken,
9+
updateUser,
10+
setUserIsAuthenticated,
11+
isAuthenticated,
12+
currentUser,
13+
} = useAuth();
14+
const [email, setEmail] = useState('');
15+
const [password, setPassword] = useState('');
16+
17+
useEffect(() => {
18+
console.log(currentUser);
19+
}, [currentUser]);
20+
useEffect(() => {
21+
console.log(isAuthenticated);
22+
}, [isAuthenticated]);
23+
24+
const handleLogin = async () => {
25+
console.log(await getToken());
26+
const tokenObtained = await login(email, password, 'Test-Device');
27+
console.log(tokenObtained);
28+
if (tokenObtained) {
29+
const user = await updateUser();
30+
if (user && user.id) {
31+
setUserIsAuthenticated(true);
32+
}
33+
}
34+
};
35+
36+
return (
37+
<View style={styles.view}>
38+
<Text style={styles.caption}>You are not logged in.</Text>
39+
<TextInput
40+
style={styles.textInput}
41+
onChangeText={(text) => setEmail(text)}
42+
value={email}
43+
placeholder="Email"
44+
/>
45+
<TextInput
46+
style={styles.textInput}
47+
onChangeText={(text) => setPassword(text)}
48+
value={password}
49+
secureTextEntry
50+
placeholder="Password"
51+
/>
52+
<Pressable style={styles.button} onPress={handleLogin}>
53+
<Text style={styles.buttonText}>Login</Text>
54+
</Pressable>
55+
</View>
56+
);
57+
}
58+
59+
function Logout() {
60+
const { logout, setUserIsAuthenticated, updateUser, currentUser } = useAuth();
61+
62+
const handleLogout = async () => {
63+
const isLoggedOut = await logout();
64+
if (isLoggedOut) {
65+
setUserIsAuthenticated(false);
66+
await updateUser();
67+
}
68+
};
69+
70+
return (
71+
<View style={styles.view}>
72+
<Text style={styles.caption}>
73+
You are logged in as {currentUser ? currentUser.name : ''}
74+
</Text>
75+
<Pressable style={styles.button} onPress={handleLogout}>
76+
<Text style={styles.buttonText}>Logout</Text>
77+
</Pressable>
78+
</View>
79+
);
80+
}
81+
82+
function Example() {
83+
const { isAuthenticated } = useAuth();
84+
return (
85+
<View style={styles.view}>{isAuthenticated ? <Logout /> : <Login />}</View>
86+
);
87+
}
88+
89+
export default function App() {
90+
const config = {
91+
loginUrl: 'http://127.0.0.1:8000/api/sanctum/token',
92+
logoutUrl: 'http://127.0.0.1:8000/api/logout',
93+
userUrl: 'http://127.0.0.1:8000/api/user',
94+
};
95+
96+
return (
97+
<AuthProvider config={config}>
98+
<View style={styles.container}>
99+
<Example />
100+
</View>
101+
</AuthProvider>
102+
);
103+
}
104+
105+
const styles = StyleSheet.create({
106+
container: {
107+
flex: 1,
108+
backgroundColor: '#fff',
109+
alignItems: 'center',
110+
justifyContent: 'center',
111+
},
112+
button: {
113+
backgroundColor: '#f59e0b',
114+
padding: 12,
115+
minWidth: '80%',
116+
borderRadius: 5,
117+
alignItems: 'center',
118+
},
119+
buttonText: {
120+
fontWeight: '800',
121+
letterSpacing: 0.5,
122+
lineHeight: 20,
123+
color: '#fff',
124+
},
125+
textInput: {
126+
height: 40,
127+
borderColor: 'gray',
128+
borderWidth: 1,
129+
minWidth: '80%',
130+
padding: 10,
131+
borderRadius: 5,
132+
marginBottom: 10,
133+
},
134+
caption: {
135+
marginBottom: 10,
136+
fontWeight: '800',
137+
letterSpacing: 0.5,
138+
lineHeight: 20,
139+
color: '#000',
140+
textAlign: 'center',
141+
},
142+
view: {
143+
padding: 15,
144+
alignItems: 'center',
145+
},
146+
});

example/tsconfig.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "../tsconfig",
3+
"compilerOptions": {
4+
// Avoid expo-cli auto-generating a tsconfig
5+
}
6+
}

example/webpack.config.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const path = require('path');
2+
const createExpoWebpackConfigAsync = require('@expo/webpack-config');
3+
const { resolver } = require('./metro.config');
4+
5+
const root = path.resolve(__dirname, '..');
6+
const node_modules = path.join(__dirname, 'node_modules');
7+
8+
module.exports = async function (env, argv) {
9+
const config = await createExpoWebpackConfigAsync(env, argv);
10+
11+
config.module.rules.push({
12+
test: /\.(js|jsx|ts|tsx)$/,
13+
include: path.resolve(root, 'src'),
14+
use: 'babel-loader',
15+
});
16+
17+
// We need to make sure that only one version is loaded for peerDependencies
18+
// So we alias them to the versions in example's node_modules
19+
Object.assign(config.resolve.alias, {
20+
...resolver.extraNodeModules,
21+
'react-native-web': path.join(node_modules, 'react-native-web'),
22+
});
23+
24+
return config;
25+
};

package-lock.json

+31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"typecheck": "tsc --noEmit",
3232
"lint": "eslint \"**/*.{js,ts,tsx}\"",
3333
"prepack": "bob build",
34+
"example": "yarn --cwd example",
3435
"release": "release-it"
3536
},
3637
"keywords": [

0 commit comments

Comments
 (0)