@boneframework/native-components 1.0.25 → 1.0.27

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,16 +4,12 @@ import {Image as ExpoImage} from "expo-image";
4
4
  import useAuth from "../hooks/useAuth";
5
5
  import settings from '../../../../config/api';
6
6
 
7
- function Image({style, uri, onPress, handleError, source, ...rest}) {
7
+ function Image({style, uri, onPress, handleError = error => console.error, source, ...rest}) {
8
8
  const {user} = useAuth();
9
9
 
10
10
  const tryAgain = async error => {
11
- if (handleError !== null) {
12
- handleError();
13
- }
14
- setTimeout(() => {
15
-
16
- }, 1000);
11
+ handleError();
12
+ setTimeout(() => {}, 1000);
17
13
  };
18
14
  let imageSource;
19
15
  let protectedUri = false;
@@ -49,10 +45,6 @@ function Image({style, uri, onPress, handleError, source, ...rest}) {
49
45
  }
50
46
  }
51
47
 
52
- const styles = StyleSheet.create({
53
- container: {}
54
- })
55
-
56
48
  export default Image;
57
49
 
58
50
 
@@ -0,0 +1,7 @@
1
+ import {useEffect} from "react";
2
+
3
+ import cache from '../utility/cache'
4
+
5
+ export default useCache = () => {
6
+ return cache;
7
+ };
@@ -0,0 +1,19 @@
1
+ import {DarkTheme, DefaultTheme} from "@react-navigation/native";
2
+
3
+ import useStyle from "./useStyle";
4
+ import colors from "../../../../config/colors";
5
+
6
+ export default useNavigationTheme = () => {
7
+ const style = useStyle();
8
+ const theme = style.dark ? DarkTheme : DefaultTheme
9
+ return {
10
+ ...theme,
11
+ colors: {
12
+ ...theme.colors,
13
+ primary: style.text.color,
14
+ background: style.backgroundColor,
15
+ card: style.backgroundColor
16
+ },
17
+ dark: style.dark
18
+ }
19
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boneframework/native-components",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Expo Components for Bone Framework",
5
5
  "main": "src/Bone.ts",
6
6
  "scripts": {
@@ -39,14 +39,15 @@
39
39
  "expo-device": "^6.0.2",
40
40
  "expo-image": "^1.12.13",
41
41
  "expo-image-picker": "^15.0.7",
42
+ "expo-location": "~17.0.1",
42
43
  "expo-notifications": "^0.28.11",
43
44
  "expo-secure-store": "^13.0.2",
44
45
  "formik": "^2.4.6",
45
46
  "jwt-decode": "^4.0.0",
46
47
  "lottie-react-native": "^6.7.2",
47
48
  "react": "18.2.0",
49
+ "react-native-maps": "^1.17.3",
48
50
  "react-native-progress": "^5.0.1",
49
- "yup": "^1.4.0",
50
- "expo-location": "~17.0.1"
51
+ "yup": "^1.4.0"
51
52
  }
52
53
  }
@@ -0,0 +1,249 @@
1
+ import React, {useEffect, useState} from 'react';
2
+ import {
3
+ Alert,
4
+ Button,
5
+ KeyboardAvoidingView,
6
+ Platform,
7
+ ScrollView,
8
+ StyleSheet,
9
+ TouchableWithoutFeedback,
10
+ View
11
+ } from "react-native"
12
+ import {Field} from "formik";
13
+ import * as FileSystem from 'expo-file-system';
14
+ import {useAsyncStorage} from "@react-native-async-storage/async-storage";
15
+ import * as Yup from "yup";
16
+
17
+ import colors from '../../../../config/colors';
18
+ import ImageInput from '../components/ImageInput';
19
+ import Image from '../components/Image';
20
+ import Screen from '../components/Screen';
21
+ import Text from '../components/Text';
22
+ import {Form, FormDateTimePicker, FormField, SubmitButton} from "../components/forms";
23
+ import ActivityIndicator from "../components/ActivityIndicator";
24
+ import UploadScreen from "./UploadScreen";
25
+ import useApi from "../hooks/useApi";
26
+ import userApi from "../api/users";
27
+ import useAuth from "../hooks/useAuth";
28
+ import useCache from "../hooks/useCache";
29
+ import useCamera from "../hooks/useCamera";
30
+ import usePhotos from "../hooks/usePhotos";
31
+ import useStyle from "../hooks/useStyle";
32
+
33
+ const validationSchema = Yup.object().shape({
34
+ firstname: Yup.string().required().min(2).max(60).label('First name'),
35
+ middlename: Yup.string().min(1).max(60).label('Middle name'),
36
+ lastname: Yup.string().required().min(1).max(60).label('Last name'),
37
+ aka: Yup.string().min(1).max(50).label('Display name'),
38
+ dob: Yup.date().required().label('Date of birth'),
39
+ birthplace: Yup.string().required().label('Birthplace'),
40
+ country: Yup.string().required().min(2).max(3).label('Country')
41
+ });
42
+
43
+ function EditProfileScreen(props) {
44
+ const [progressVisible, setProgressVisible] = useState(false);
45
+ const [progress, setProgress] = useState(0);
46
+ const [profileImage, setProfileImage] = useState(null);
47
+ const [profileBackground, setProfileBackground] = useState(null);
48
+ const style = useStyle();
49
+
50
+ const { updateUser, user} = useAuth();
51
+ const updateProfileApi = useApi(userApi.updateProfile);
52
+ const userImageUploadApi = useApi(userApi.uploadUserImage);
53
+ const userImageApi = useApi(userApi.userImage);
54
+ const userBackgroundImageUploadApi = useApi(userApi.uploadUserBackgroundImage);
55
+ const userBackgroundImageApi = useApi(userApi.userBackgroundImage);
56
+ const camera = useCamera();
57
+ const photos = usePhotos();
58
+ const person = user.person;
59
+
60
+ useEffect(() => {
61
+ if(!profileImage) {
62
+ setProfileImage(user.person.image);
63
+ }
64
+ if(!profileImage) {
65
+ setProfileBackground(user.person.backgroundImage);
66
+ }
67
+ }, [])
68
+
69
+ const handleSubmit = values => {
70
+ updateProfileApi.request(values)
71
+ .then(data => {
72
+ user.person = data.data;
73
+ updateUser(user);
74
+
75
+ })
76
+ .catch(console.error)
77
+ };
78
+
79
+ const cameraOrPhotos = phptoOrBackground => {
80
+ const title = phptoOrBackground === 'image' ? 'Edit Profile Photo' : 'Edit Profile Background'
81
+ Alert.alert(
82
+ title,
83
+ null,
84
+ [
85
+ { text: 'Photos', onPress: () => selectImage('photos', phptoOrBackground) },
86
+ { text: 'Camera', onPress: () => selectImage('camera', phptoOrBackground) },
87
+ { text: 'Cancel', style: 'cancel' }
88
+ ]
89
+ );
90
+ }
91
+
92
+ const selectImage = async (pickerType, phptoOrBackground) => {
93
+ try {
94
+ if (pickerType === 'camera') {
95
+ const result = await camera.takePhoto({
96
+ allowsEditing: true,
97
+ base64: true,
98
+ quality: 0.5
99
+ });
100
+ if (!result.canceled) {
101
+ handleSelection(result.assets[0].uri, phptoOrBackground);
102
+ }
103
+ } else {
104
+ const result = await photos.selectImage({
105
+ quality: 0.5,
106
+ base64: true
107
+ });
108
+
109
+ if (!result.canceled) {
110
+ handleSelection(result.assets[0].uri, phptoOrBackground);
111
+ }
112
+ }
113
+
114
+ } catch (error) {
115
+ Alert.alert('Image error', 'Error reading image');
116
+ console.error(error);
117
+ }
118
+ };
119
+
120
+ const handleSelection = (uri, phptoOrBackground) => {
121
+ if (phptoOrBackground === 'background-image') {
122
+ uploadImage(uri, userBackgroundImageUploadApi, 'background');
123
+ setProfileBackground(uri);
124
+ user.person.backgroundImage = uri;
125
+ } else {
126
+ uploadImage(uri, userImageUploadApi, 'avatar');
127
+ setProfileImage(uri);
128
+ user.person.image = uri;
129
+ }
130
+ updateUser(user);
131
+ }
132
+
133
+ const uploadImage = async (url, api, fieldName) => {
134
+ let formData = new FormData();
135
+ let filename = url.split('/').pop();
136
+ let match = /\.(\w+)$/.exec(filename);
137
+ let type = match ? `image/${match[1]}` : `image`;
138
+ formData.append(fieldName, { uri: url, name: filename, type });
139
+ const response = await api.request(formData).catch(e => {
140
+ console.error('upload error', e);
141
+ });
142
+ }
143
+
144
+ const styles = StyleSheet.create({
145
+ container: {
146
+ backgroundColor: style.backgroundColor
147
+ },
148
+ wallpaper: {
149
+ height: 240,
150
+ width: '100%',
151
+ backgroundColor: colors.secondary
152
+ },
153
+ image: {
154
+ width: 150,
155
+ height: 150,
156
+ borderRadius: 75,
157
+ marginTop: -75,
158
+ borderColor: colors.white,
159
+ borderWidth: 7,
160
+ backgroundColor: colors.light,
161
+ },
162
+ fullWidth: {
163
+ width: '100%'
164
+ },
165
+ centred: {
166
+ width: '100%',
167
+ },
168
+ imageContainer: {
169
+ alignItems: "center",
170
+ width: '100%',
171
+ }
172
+ })
173
+
174
+ return (
175
+ <>
176
+ <KeyboardAvoidingView
177
+ behavior="position"
178
+ keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 140}
179
+ style={styles.container}
180
+ >
181
+ <ActivityIndicator visible={updateProfileApi.loading || userImageApi.loading || userImageUploadApi.loading || userBackgroundImageApi.loading || userBackgroundImageUploadApi.loading } type={'overlay'}/>
182
+ <UploadScreen onDone={() => setProgressVisible(false)} progress={progress} visible={progressVisible}/>
183
+ <ScrollView contentContainerStyle={styles.centred}>
184
+ <TouchableWithoutFeedback onPress={() => {cameraOrPhotos('background-image')}} >
185
+ <View style={styles.wallpaper}>
186
+ <Image style={styles.wallpaper} uri={profileBackground} />
187
+ </View>
188
+ </TouchableWithoutFeedback>
189
+
190
+ <TouchableWithoutFeedback onPress={() => {cameraOrPhotos('image')}} >
191
+ <View style={styles.imageContainer}>
192
+ <Image style={styles.image} uri={profileImage} />
193
+ </View>
194
+ </TouchableWithoutFeedback>
195
+
196
+ <Form
197
+ initialValues={{
198
+ firstname: person.firstname,
199
+ middlename: person.middlename,
200
+ lastname: person.lastname,
201
+ aka: person.aka,
202
+ dob: person.dob ? new Date(person.dob) : new Date(),
203
+ birthplace: person.birthplace,
204
+ image: person.image,
205
+ country: person.country?.iso,
206
+ }}
207
+ onSubmit={handleSubmit}
208
+ validationSchema={validationSchema}
209
+ >
210
+ <FormField
211
+ name="firstname"
212
+ placeholder="First name"
213
+ maxLength={60}
214
+ />
215
+ <FormField
216
+ name="middlename"
217
+ placeholder="Middle name"
218
+ maxLength={60}
219
+ />
220
+ <FormField
221
+ name="lastname"
222
+ placeholder="Last name"
223
+ maxLength={60}
224
+ />
225
+ <FormField
226
+ name="aka"
227
+ placeholder="Display name"
228
+ maxLength={50}
229
+ />
230
+ <FormDateTimePicker name={'dob'}/>
231
+ <FormField
232
+ name="birthplace"
233
+ placeholder="Birthplace"
234
+ maxLength={50}
235
+ />
236
+ <FormField
237
+ name="country"
238
+ placeholder="Country"
239
+ maxLength={3}
240
+ />
241
+ <SubmitButton color="primary" title="Update profile"/>
242
+ </Form>
243
+ </ScrollView>
244
+ </KeyboardAvoidingView>
245
+ </>
246
+ );
247
+ }
248
+
249
+ export default EditProfileScreen;