@boneframework/native-components 1.0.28 → 1.0.30
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.
|
@@ -4,7 +4,7 @@ import {View, StyleSheet} from "react-native";
|
|
|
4
4
|
import Animation from "./Animation";
|
|
5
5
|
import useStyle from "../hooks/useStyle";
|
|
6
6
|
|
|
7
|
-
function ActivityIndicator({ visible = false , type="default"}) {
|
|
7
|
+
function ActivityIndicator({ visible = false , type="default", animationPath = '../../../../assets/animations/loader.json'}) {
|
|
8
8
|
const defaultStyles = useStyle();
|
|
9
9
|
|
|
10
10
|
const styles = StyleSheet.create({
|
|
@@ -35,7 +35,7 @@ function ActivityIndicator({ visible = false , type="default"}) {
|
|
|
35
35
|
return (
|
|
36
36
|
<View style={style}>
|
|
37
37
|
<Animation
|
|
38
|
-
source={require(
|
|
38
|
+
source={require(animationPath)}
|
|
39
39
|
autoPlay={true}
|
|
40
40
|
loop={true}
|
|
41
41
|
style={{height: 100, width: 100, opacity: 1}}
|
package/components/Animation.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, {useEffect, useRef} from 'react';
|
|
2
2
|
import LottieView from "lottie-react-native";
|
|
3
3
|
|
|
4
|
-
function Animation({source, style, onAnimationFinish, autoPlay = true, loop = true, speed = 1.5}) {
|
|
4
|
+
function Animation({source, style = {}, onAnimationFinish = () => {}, autoPlay = true, loop = true, speed = 1.5}) {
|
|
5
5
|
|
|
6
6
|
const lottieRef = useRef(null);
|
|
7
7
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as Linking from "expo-linking";
|
|
2
|
+
import {useEffect} from "react";
|
|
3
|
+
import router from 'ex';
|
|
4
|
+
|
|
5
|
+
import routes from '../../../../config/routes';
|
|
6
|
+
|
|
7
|
+
export default useLinking = () => {
|
|
8
|
+
const url = Linking.useURL();
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (url) {
|
|
12
|
+
const parts = Linking.parse(url);
|
|
13
|
+
if (parts.path !== null && parts.path !== '') {
|
|
14
|
+
switch (parts.path) {
|
|
15
|
+
case routes.USER_ACTIVATION:
|
|
16
|
+
router.navigate(routes.USER_ACTIVATION, parts.queryParams);
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}, [url]);
|
|
22
|
+
|
|
23
|
+
return url;
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boneframework/native-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "Expo Components for Bone Framework",
|
|
5
5
|
"main": "src/Bone.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"expo-image-picker": "^15.0.7",
|
|
42
42
|
"expo-location": "~17.0.1",
|
|
43
43
|
"expo-notifications": "^0.28.11",
|
|
44
|
+
"expo-router": "^3.5.23",
|
|
44
45
|
"expo-secure-store": "^13.0.2",
|
|
45
46
|
"formik": "^2.4.6",
|
|
46
47
|
"jwt-decode": "^4.0.0",
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {Image, ImageBackground, Keyboard, StyleSheet, View} from "react-native";
|
|
2
|
+
import * as Linking from 'expo-linking';
|
|
3
|
+
import React, {useEffect, useState} from "react";
|
|
4
|
+
import * as Yup from 'yup'
|
|
5
|
+
|
|
6
|
+
import Button from '../components/Button';
|
|
7
|
+
import CheckEmailScreen from '../screens/CheckEmailScreen';
|
|
8
|
+
import Text from '../components/Text';
|
|
9
|
+
import ActivityIndicator from "../components/ActivityIndicator";
|
|
10
|
+
import Animation from "../components/Animation";
|
|
11
|
+
import {ErrorMessage, Form, FormField, SubmitButton} from "../components/forms";
|
|
12
|
+
import ResendActivationScreen from "../screens/ResendActivationlScreen";
|
|
13
|
+
import SetPasswordScreen from "../screens/SetPasswordScreen";
|
|
14
|
+
import useApi from "../hooks/useApi";
|
|
15
|
+
import useAuth from "../hooks/useAuth";
|
|
16
|
+
import useLinking from "../hooks/useLinking";
|
|
17
|
+
import userApi from "../api/users";
|
|
18
|
+
|
|
19
|
+
import settings from "../../../../config/settings";
|
|
20
|
+
import routes from "../../../../config/routes";
|
|
21
|
+
import colors from '../../../../config/colors';
|
|
22
|
+
|
|
23
|
+
function ActivateUserScreen({navigation, route}) {
|
|
24
|
+
const STATUS_VALIDATE = 'validate_email_token';
|
|
25
|
+
const STATUS_RESEND = 'resend_email_token';
|
|
26
|
+
const STATUS_SET_PASSWORD = 'set_password';
|
|
27
|
+
const activationApi = useApi(userApi.activateAccount);
|
|
28
|
+
const resendActivationApi = useApi(userApi.resendactivationEmail);
|
|
29
|
+
const validateEmailTokenApi = useApi(userApi.validateEmailToken);
|
|
30
|
+
const [status, setStatus] = useState(STATUS_VALIDATE);
|
|
31
|
+
const [error, setError] = useState();
|
|
32
|
+
const [tokenError, setTokenError] = useState();
|
|
33
|
+
const {login} = useAuth();
|
|
34
|
+
const url = Linking.useURL();
|
|
35
|
+
const email = route.params.email;
|
|
36
|
+
const token = route.params.token;
|
|
37
|
+
|
|
38
|
+
const validateEmailToken = async () => {
|
|
39
|
+
const result = await validateEmailTokenApi.request(email, token);
|
|
40
|
+
|
|
41
|
+
if (result.data.ok) {
|
|
42
|
+
setStatus(STATUS_SET_PASSWORD);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (result.data.error) {
|
|
46
|
+
setTokenError(result.data.error);
|
|
47
|
+
|
|
48
|
+
switch (result.data.error) {
|
|
49
|
+
case 'The email link has expired.':
|
|
50
|
+
setStatus(STATUS_RESEND);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const handleSubmit = async userInfo => {
|
|
57
|
+
Keyboard.dismiss();
|
|
58
|
+
try {
|
|
59
|
+
const result = await activationApi.request(email, token, settings.clientId, userInfo.password);
|
|
60
|
+
|
|
61
|
+
if (!result.ok) {
|
|
62
|
+
if (result.data) {
|
|
63
|
+
switch (result.data.error) {
|
|
64
|
+
case 'The email link has expired.':
|
|
65
|
+
case 'A matching email link was not found':
|
|
66
|
+
case 'The token did not match.':
|
|
67
|
+
setTokenError(result.data.error);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
setError(result.data.error);
|
|
71
|
+
} else {
|
|
72
|
+
setError('An unexpected error occured');
|
|
73
|
+
console.error(result);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
login({accessToken: result.data.access_token, refreshToken: result.data.refresh_token});
|
|
80
|
+
} catch (error) {
|
|
81
|
+
setError(error);
|
|
82
|
+
console.error(error);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const resendActivationEmail = async () => {
|
|
88
|
+
resendActivationApi
|
|
89
|
+
.request(email)
|
|
90
|
+
.then(setStatus(STATUS_VALIDATE))
|
|
91
|
+
.then(navigation.goBack())
|
|
92
|
+
.then(navigation.navigate(routes.USER_ACTIVATION_CHECK_EMAIL))
|
|
93
|
+
.catch(console.error);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (status === STATUS_VALIDATE) {
|
|
98
|
+
validateEmailToken();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<>
|
|
104
|
+
<ActivityIndicator visible={activationApi.loading || resendActivationApi.loading || validateEmailTokenApi.loading} type={'overlay'}/>
|
|
105
|
+
<ImageBackground blurRadius={10} style={styles.container} source={require('../../../../assets/background.png')} >
|
|
106
|
+
{ (status === STATUS_SET_PASSWORD || status === STATUS_VALIDATE) && <SetPasswordScreen submitCallback={handleSubmit} error={error}/> }
|
|
107
|
+
{ status === STATUS_RESEND && <ResendActivationScreen email={email} tokenError={tokenError} submitCallback={resendActivationEmail}/> }
|
|
108
|
+
</ImageBackground>
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const styles = StyleSheet.create({
|
|
114
|
+
container: {
|
|
115
|
+
flex: 1,
|
|
116
|
+
paddingHorizontal: 20
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
export default ActivateUserScreen;
|
|
121
|
+
|
|
122
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {ImageBackground, StyleSheet, View} from "react-native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
import Text from '../components/Text';
|
|
5
|
+
import Animation from "../components/Animation";
|
|
6
|
+
|
|
7
|
+
import colors from "../../../../config/colors";
|
|
8
|
+
|
|
9
|
+
function CheckEmailScreen(props) {
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<ImageBackground blurRadius={10} style={styles.container} source={require('../../../../assets/background.png')} >
|
|
13
|
+
<View style={styles.animationContainer}>
|
|
14
|
+
<Animation
|
|
15
|
+
autoPlay={true}
|
|
16
|
+
loop={true}
|
|
17
|
+
source={require('../../../../assets/animations/email.json')}
|
|
18
|
+
style={styles.animation}
|
|
19
|
+
speed={1}
|
|
20
|
+
/>
|
|
21
|
+
<Text style={styles.activate}>Activate your account</Text>
|
|
22
|
+
<Text style={styles.info}>Check your email and click on the link to open the app and activate your account.</Text>
|
|
23
|
+
</View>
|
|
24
|
+
</ImageBackground>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const styles = StyleSheet.create({
|
|
29
|
+
container: {
|
|
30
|
+
flex: 1,
|
|
31
|
+
paddingHorizontal: 20
|
|
32
|
+
},
|
|
33
|
+
animationContainer: {
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
justifyContent: 'center',
|
|
36
|
+
flex: 1,
|
|
37
|
+
paddingHorizontal: 10,
|
|
38
|
+
marginTop: -50
|
|
39
|
+
},
|
|
40
|
+
animation: {
|
|
41
|
+
width: 150,
|
|
42
|
+
height: 150,
|
|
43
|
+
},
|
|
44
|
+
activate: {
|
|
45
|
+
marginTop: 20,
|
|
46
|
+
textTransform: 'uppercase',
|
|
47
|
+
fontSize: 24,
|
|
48
|
+
fontWeight: 'bold',
|
|
49
|
+
marginBottom: 20,
|
|
50
|
+
color: colors.white,
|
|
51
|
+
textAlign: 'center'
|
|
52
|
+
},
|
|
53
|
+
info: {
|
|
54
|
+
color: colors.white,
|
|
55
|
+
textAlign: 'center'
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
export default CheckEmailScreen;
|