@boneframework/native-components 1.0.15 → 1.0.17

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # @boneframework/native-components
2
- React Native expo components for BoneFramework WIP
2
+ React Native expo components for BoneFramework
3
3
  ## project level files referred to in code
4
4
  ```
5
5
  config/settings
@@ -1,22 +1,51 @@
1
- import React, {useState} from 'react';
1
+ import React, {useEffect, useState} from 'react';
2
2
 
3
- import AuthContext from "../contexts/auth";
4
- import useAuth from "../hooks/useAuth";
3
+ import AuthContext from "@boneframework/native-components/contexts/auth";
4
+ import useAuth from "@boneframework/native-components/hooks/useAuth";
5
+ import {useSecureStorageState} from "@boneframework/native-components/hooks/useSecureStorageState";
6
+ import {useStorageState} from "@boneframework/native-components/hooks/useStorageState";
7
+ import authStorage from "@boneframework/native-components/utilities/authStorage";
8
+ import useApi from "@boneframework/native-components/hooks/useApi";
9
+ import usersApi from "@boneframework/native-components/api/users";
5
10
 
6
11
  function SessionProvider(props: object) {
7
- const {login, logout, updateUser, user, isLoading} = useAuth();
12
+ const profileApi = useApi(usersApi.getProfile);
13
+ const [[isAuthTokenLoading, authToken], setAuthToken] = useSecureStorageState('authToken');
14
+ const [[isUserLoading, user], setUser] = useStorageState('user');
15
+ const [isLoading, setIsLoading] = useState(false);
16
+
17
+ useEffect(() => {
18
+ setIsLoading(profileApi.loading || isAuthTokenLoading || isUserLoading);
19
+ }, [profileApi.loading || isAuthTokenLoading || isUserLoading]);
20
+
8
21
 
9
22
  return (
10
23
  <AuthContext.Provider
11
24
  value={{
12
- signIn: async (authToken: string) => {
13
- login(authToken);
25
+ login: async (authToken: object) => {
26
+ setIsLoading(true);
27
+ await authStorage.storeAuthToken(authToken).then(async () => {
28
+ const userProfile = await profileApi.request(authToken.accessToken);
29
+ userProfile.data.authToken = authToken;
30
+ setAuthToken(authToken)
31
+ await setUser(userProfile.data);
32
+ setIsLoading(false);
33
+ console.log('token : ', authToken)
34
+ console.log('user : ', user)
35
+ console.log('profile : ', userProfile.data)
36
+ console.log('user : ', user)
37
+
38
+ });
39
+ },
40
+ logout: () => {
41
+ setAuthToken(null);
42
+ setUser(null);
14
43
  },
15
- signOut: () => {
16
- logout();
44
+ updateUser: async data => {
45
+ setUser(data)
17
46
  },
18
- update: data => updateUser(data),
19
47
  user,
48
+ isLoading
20
49
  }}>
21
50
  {props.children}
22
51
  </AuthContext.Provider>
package/contexts/auth.ts CHANGED
@@ -5,13 +5,13 @@ const AuthContext = createContext<{
5
5
  logout: () => void;
6
6
  updateUser: () => void;
7
7
  user?: object | null;
8
- isLoading: boolean;
8
+ isLoading: bool;
9
9
  }>({
10
10
  login: () => null,
11
11
  logout: () => null,
12
12
  updateUser: () => null,
13
13
  user: null,
14
- isLoading: false,
14
+ isLoading: true
15
15
  });
16
16
 
17
17
  export default AuthContext;
package/hooks/useAuth.ts CHANGED
@@ -6,36 +6,13 @@ import useApi from "./useApi";
6
6
  import usersApi from "../api/users";
7
7
 
8
8
  export default useAuth = () => {
9
- const profileApi = useApi(usersApi.getProfile);
10
- const {user, setUser} = useContext(AuthContext);
11
- const {isLoading, setIsLoading} = useState(false);
9
+ const value = useContext(AuthContext);
12
10
 
13
- const login = async authToken => {
14
- setIsLoading(true);
15
- await authStorage.storeAuthToken(authToken).then(async () => {
16
- const user = await profileApi.request(authToken);
17
- authStorage.storeUser(user.data);
18
- user.data.authToken = authToken;
19
- setUser(user.data);
20
- setIsLoading(false);
21
- });
11
+ if (process.env.NODE_ENV !== 'production') {
12
+ if (!value) {
13
+ throw new Error('useSession must be wrapped in a <SessionProvider />');
14
+ }
22
15
  }
23
16
 
24
- const updateUser = async user => {
25
- setIsLoading(true);
26
- const authToken = user.authToken;
27
- await delete user.authToken;
28
- authStorage.storeUser(user);
29
- user.authToken = authToken;
30
- setUser({...user});
31
- setIsLoading(false);
32
- }
33
-
34
- const logout = () => {
35
- setUser(null);
36
- authStorage.removeAuthToken();
37
- authStorage.removeUser();
38
- }
39
-
40
- return {login, logout, updateUser, user, isLoading};
17
+ return value;
41
18
  }
@@ -0,0 +1,95 @@
1
+ import * as SecureStore from 'expo-secure-store';
2
+ import * as React from 'react';
3
+ import { Platform } from 'react-native';
4
+
5
+ type UseStateHook<T> = [[boolean, T | null], (value: T | null) => void];
6
+
7
+ function useAsyncState<T>(
8
+ initialValue: [boolean, T | null] = [true, null],
9
+ ): UseStateHook<T> {
10
+ return React.useReducer(
11
+ (state: [boolean, T | null], action: T | null = null): [boolean, T | null] => [false, action],
12
+ initialValue
13
+ ) as UseStateHook<T>;
14
+ }
15
+
16
+ export async function setStorageItemAsync(key: string, value: string | null) {
17
+ if (typeof value === 'object') {
18
+ value = JSON.stringify(value);
19
+ }
20
+
21
+ if (Platform.OS === 'web') {
22
+ try {
23
+ if (value === null) {
24
+ localStorage.removeItem(key);
25
+ } else {
26
+ localStorage.setItem(key, value);
27
+ }
28
+ } catch (e) {
29
+ console.error('Local storage is unavailable:', e);
30
+ }
31
+ } else {
32
+ if (value == null) {
33
+ await SecureStore.deleteItemAsync(key);
34
+ } else {
35
+ await SecureStore.setItemAsync(key, value);
36
+ }
37
+ }
38
+ }
39
+
40
+ export function useSecureStorageState(key: string): UseStateHook<string> {
41
+ // Public
42
+ const [state, setState] = useAsyncState<string|object>();
43
+
44
+ const isJson = () => {
45
+ try {
46
+ const result = JSON.parse(str);
47
+ const type = Object.prototype.toString.call(result);
48
+ return type === '[object Object]'
49
+ || type === '[object Array]';
50
+ } catch (err) {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ // Get
56
+ React.useEffect(() => {
57
+ if (Platform.OS === 'web') {
58
+ try {
59
+ if (typeof localStorage !== 'undefined') {
60
+ value = localStorage.getItem(key);
61
+
62
+ if (isJson(value)) {
63
+ value = JSON.parse(value);
64
+ }
65
+
66
+ setState(value);
67
+ }
68
+ } catch (e) {
69
+ console.error('Local storage is unavailable:', e);
70
+ }
71
+ } else {
72
+ console.log('fetching ' + key);
73
+ SecureStore.getItemAsync(key).then(value => {
74
+ console.log('value', value)
75
+ if (isJson(value)) {
76
+ value = JSON.parse(value);
77
+ }
78
+
79
+ setState(value);
80
+ console.log('state ', state)
81
+ });
82
+ }
83
+ }, [key]);
84
+
85
+ // Set
86
+ const setValue = React.useCallback(
87
+ (value: string | null) => {
88
+ setState(value);
89
+ setStorageItemAsync(key, value);
90
+ },
91
+ [key]
92
+ );
93
+
94
+ return [state, setValue];
95
+ }
@@ -0,0 +1,95 @@
1
+ import AsyncStorage from "@react-native-async-storage/async-storage";
2
+ import * as React from 'react';
3
+ import { Platform } from 'react-native';
4
+
5
+ type UseStateHook<T> = [[boolean, T | null], (value: T | null) => void];
6
+
7
+ function useAsyncState<T>(
8
+ initialValue: [boolean, T | null] = [true, null],
9
+ ): UseStateHook<T> {
10
+ return React.useReducer(
11
+ (state: [boolean, T | null], action: T | null = null): [boolean, T | null] => [false, action],
12
+ initialValue
13
+ ) as UseStateHook<T>;
14
+ }
15
+
16
+
17
+
18
+ export async function setStorageItemAsync(key: string, value: object | string | null) {
19
+ if (typeof value === 'object') {
20
+ value = JSON.stringify(value);
21
+ }
22
+
23
+ if (Platform.OS === 'web') {
24
+ try {
25
+ if (value === null) {
26
+ localStorage.removeItem(key);
27
+ } else {
28
+ localStorage.setItem(key, value);
29
+ }
30
+ } catch (e) {
31
+ console.error('Local storage is unavailable:', e);
32
+ }
33
+ } else {
34
+ if (value == null) {
35
+ await AsyncStorage.removeItem(key);
36
+ } else {
37
+ await AsyncStorage.setItem(key, value);
38
+ }
39
+ }
40
+ }
41
+
42
+ export function useStorageState(key: string): UseStateHook<string> {
43
+ const isJson = () => {
44
+ try {
45
+ const result = JSON.parse(str);
46
+ const type = Object.prototype.toString.call(result);
47
+ return type === '[object Object]'
48
+ || type === '[object Array]';
49
+ } catch (err) {
50
+ return false;
51
+ }
52
+ }
53
+ // Public
54
+ const [state, setState] = useAsyncState<string|object>();
55
+ // Get
56
+
57
+ React.useEffect(() => {
58
+ if (Platform.OS === 'web') {
59
+ try {
60
+ if (typeof localStorage !== 'undefined') {
61
+ value = localStorage.getItem(key);
62
+
63
+ if (isJson(value)) {
64
+ value = JSON.parse(value);
65
+ }
66
+
67
+ setState(value);
68
+ }
69
+ } catch (e) {
70
+ console.error('Local storage is unavailable:', e);
71
+ }
72
+ } else {
73
+ AsyncStorage.getItem(key).then(value => {
74
+
75
+ if (isJson(value)) {
76
+ value = JSON.parse(value);
77
+ }
78
+
79
+ setState(value);
80
+ });
81
+ }
82
+ }, [key]);
83
+
84
+
85
+ // Set
86
+ const setValue = React.useCallback(
87
+ (value: object | string | null) => {
88
+ setState(value);
89
+ setStorageItemAsync(key, value);
90
+ },
91
+ [key]
92
+ );
93
+
94
+ return [state, setValue];
95
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boneframework/native-components",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Expo Components for Bone Framework",
5
5
  "main": "src/Bone.ts",
6
6
  "scripts": {
@@ -31,6 +31,7 @@
31
31
  "dependencies": {
32
32
  "@react-native-async-storage/async-storage": "^1.24.0",
33
33
  "@react-native-community/datetimepicker": "^8.2.0",
34
+ "@react-native-community/netinfo": "^11.3.2",
34
35
  "apisauce": "^3.0.1",
35
36
  "expo-auth-session": "^5.5.2",
36
37
  "expo-camera": "^15.0.13",
@@ -4,10 +4,12 @@ import {exchangeCodeAsync, makeRedirectUri, useAuthRequest} from "expo-auth-sess
4
4
 
5
5
  import Button from '../components/Button'
6
6
  import colors from '../../../../config/colors'
7
+ import ActivityIndicator from "@boneframework/native-components/components/ActivityIndicator";
7
8
 
8
- function WelcomeScreen({loginOnPress = () => {}, registerOnPress = () => {}, title = 'BONE FRAMEWORK'}) {
9
+ function WelcomeScreen({loginOnPress = () => {}, registerOnPress = () => {}, title = 'BONE FRAMEWORK', isLoading = false}) {
9
10
  return (
10
11
  <ImageBackground blurRadius={10} style={styles.background} source={require('../../../../assets/background.png')} >
12
+ <ActivityIndicator visible={isLoading} type={'overlay'}/>
11
13
  <View style={styles.logoContainer}>
12
14
  <Image style={styles.logo} source={require('../../../../assets/logo.png')} />
13
15
  <Text style={styles.tagline}>{ title }</Text>
@@ -0,0 +1,13 @@
1
+ const hasJsonStructure = (str) => {
2
+ if (typeof str !== 'string') return false;
3
+ try {
4
+ const result = JSON.parse(str);
5
+ const type = Object.prototype.toString.call(result);
6
+ return type === '[object Object]'
7
+ || type === '[object Array]';
8
+ } catch (err) {
9
+ return false;
10
+ }
11
+ }
12
+
13
+ export default {hasJsonStructure};
package/Bone.ts DELETED
@@ -1,6 +0,0 @@
1
- import Components from "./Components";
2
- import Hooks from "./Hooks";
3
- import Screens from "./Screens";
4
- import Utilities from "./Utilities";
5
-
6
- export default {Components, Hooks, Screens, Utilities}
package/Components.ts DELETED
@@ -1 +0,0 @@
1
- export default {}
package/Contexts.ts DELETED
@@ -1 +0,0 @@
1
- export default {}
package/Hooks.ts DELETED
@@ -1,3 +0,0 @@
1
- import useAuth from './hooks/useAuth';
2
-
3
- export default { useAuth }
package/Screens.ts DELETED
@@ -1,4 +0,0 @@
1
- import RegisterScreen from './screens/RegisterScreen'
2
- import WelcomeScreen from './screens/WelcomeScreen'
3
-
4
- export default { RegisterScreen, WelcomeScreen }
package/Utilities.ts DELETED
@@ -1 +0,0 @@
1
- export default {}