diff --git a/MobileApp/package.json b/MobileApp/package.json
index cf64248..23b7d2d 100644
--- a/MobileApp/package.json
+++ b/MobileApp/package.json
@@ -19,6 +19,7 @@
"preset": "jest-expo"
},
"dependencies": {
+ "base64-arraybuffer": "^0.1.5",
"expo": "^27.0.1",
"firebase": "^5.0.4",
"lodash": "^4.17.10",
diff --git a/MobileApp/src/components/app-navigator.js b/MobileApp/src/components/app-navigator.js
index 976330b..2a78557 100644
--- a/MobileApp/src/components/app-navigator.js
+++ b/MobileApp/src/components/app-navigator.js
@@ -1,34 +1,40 @@
-import {createStackNavigator, createBottomTabNavigator} from 'react-navigation'
+import {
+ createStackNavigator,
+ createBottomTabNavigator
+} from 'react-navigation'
import AuthScreen from './screens/auth'
import EventList from './screens/event-list'
import PeopleList from './screens/people-list'
import EventScreen from './screens/event'
import EventMapScreen from './screens/event-map'
+import PersonAvatar from './screens/person-avatar'
const ListsNavigator = createBottomTabNavigator({
- events: {
- screen: EventList
- },
- people: {
- screen: PeopleList
- }
+ events: {
+ screen: EventList
+ },
+ people: {
+ screen: PeopleList
+ }
})
-
export default createStackNavigator({
- auth: {
- screen: AuthScreen,
- navigationOptions: {
- title: 'Auth'
- }
- },
- lists: {
- screen: ListsNavigator,
- navigationOptions: {
- title: 'Lists'
- }
- },
- event: {
- screen: EventMapScreen
+ auth: {
+ screen: AuthScreen,
+ navigationOptions: {
+ title: 'Auth'
}
-})
\ No newline at end of file
+ },
+ lists: {
+ screen: ListsNavigator,
+ navigationOptions: {
+ title: 'Lists'
+ }
+ },
+ event: {
+ screen: EventMapScreen
+ },
+ personAvatar: {
+ screen: PersonAvatar
+ }
+})
diff --git a/MobileApp/src/components/people/person-avatar.js b/MobileApp/src/components/people/person-avatar.js
new file mode 100644
index 0000000..9b45f24
--- /dev/null
+++ b/MobileApp/src/components/people/person-avatar.js
@@ -0,0 +1,72 @@
+import React, { Component } from 'react'
+import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'
+import { Camera, Permissions } from 'expo'
+import { observable, action } from 'mobx'
+import { observer, inject } from 'mobx-react'
+
+@inject('people')
+@inject('navigation')
+@observer
+class PersonAvatar extends Component {
+ @observable permissionAsked = false
+ @observable permissionGranted = false
+
+ async componentDidMount() {
+ this.setPermissionAsked(true)
+ const { status } = await Permissions.askAsync(Permissions.CAMERA)
+ this.setPermissionGranted(status === 'granted')
+ }
+
+ @action setPermissionAsked = (asked) => (this.permissionAsked = asked)
+ @action setPermissionGranted = (granted) => (this.permissionGranted = granted)
+
+ render() {
+ if (!this.permissionAsked) return Not Asked
+ if (!this.permissionGranted) return Not Granted
+
+ return (
+
+
+
+
+
+
+
+ )
+ }
+
+ setRef = (ref) => {
+ this.camera = ref
+ }
+
+ takeAvatar = async () => {
+ const { uid, people, navigation } = this.props
+
+ if (this.camera) {
+ const avatar = await this.camera.takePictureAsync({ base64: true })
+ people.saveAvatar(uid, avatar)
+ }
+
+ navigation.navigate('people')
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1
+ },
+ camera: {
+ flex: 1,
+ justifyContent: 'flex-end'
+ },
+ button: {
+ marginBottom: 20,
+ width: 60,
+ height: 60,
+ backgroundColor: 'white',
+ borderRadius: 30,
+ alignSelf: 'center'
+ }
+})
+
+export default PersonAvatar
diff --git a/MobileApp/src/components/people/person-card.js b/MobileApp/src/components/people/person-card.js
index 1c6bac7..0db5e41 100644
--- a/MobileApp/src/components/people/person-card.js
+++ b/MobileApp/src/components/people/person-card.js
@@ -1,43 +1,45 @@
import React, { Component } from 'react'
-import {View, Text, Image, StyleSheet} from 'react-native'
+import { View, Text, Image, StyleSheet } from 'react-native'
import Card from '../common/card'
class PersonCard extends Component {
- static propTypes = {
+ static propTypes = {}
- };
-
- render() {
- const { email, firstName, lastName } = this.props.person
- return (
-
-
-
- {email}
- {firstName} {lastName}
-
-
- )
- }
+ render() {
+ const { email, firstName, lastName, avatar } = this.props.person
+ return (
+
+ {avatar ? (
+
+ ) : null}
+
+ {email}
+
+ {firstName} {lastName}
+
+
+
+ )
+ }
}
const styles = StyleSheet.create({
- container: {
- flexDirection: 'row'
- },
- avatar: {
- width: 200,
- height: 100,
- margin: 5
- },
- content: {
- flexDirection: 'column',
- justifyContent: 'space-around',
- alignItems: 'center'
- },
- email: {
- fontWeight: 'bold'
- }
+ container: {
+ flexDirection: 'row'
+ },
+ avatar: {
+ width: 200,
+ height: 100,
+ margin: 5
+ },
+ content: {
+ flexDirection: 'column',
+ justifyContent: 'space-around',
+ alignItems: 'center'
+ },
+ email: {
+ fontWeight: 'bold'
+ }
})
-export default PersonCard
\ No newline at end of file
+export default PersonCard
diff --git a/MobileApp/src/components/screens/people-list.js b/MobileApp/src/components/screens/people-list.js
index cea8fa0..03b6700 100644
--- a/MobileApp/src/components/screens/people-list.js
+++ b/MobileApp/src/components/screens/people-list.js
@@ -1,36 +1,41 @@
import React, { Component } from 'react'
-import {observer, inject} from 'mobx-react'
-import {View, StyleSheet, ActivityIndicator} from 'react-native'
+import { observer, inject } from 'mobx-react'
+import { View, StyleSheet, ActivityIndicator } from 'react-native'
import PeopleList from '../people/people-list'
@inject('people')
@observer
class PeopleListScreen extends Component {
- static propTypes = {
-
- };
-
- static navigationOptions = {
- title: 'People List'
- }
-
- componentDidMount() {
- const {people} = this.props
- if (!people.loaded && !people.loading) people.loadAll()
- }
-
- render() {
- const {people} = this.props
- if (people.loading) return this.getLoader()
- return
- }
-
- getLoader() {
- return
- }
+ static propTypes = {}
+
+ static navigationOptions = {
+ title: 'People List'
+ }
+
+ componentDidMount() {
+ const { people } = this.props
+ if (!people.loaded && !people.loading) people.loadAll()
+ }
+
+ render() {
+ const { people } = this.props
+ if (people.loading) return this.getLoader()
+ return
+ }
+
+ getLoader() {
+ return (
+
+
+
+ )
+ }
+
+ handlePersonPress = (uid) => {
+ this.props.navigation.navigate('personAvatar', { uid })
+ }
}
-const styles = StyleSheet.create({
-})
+const styles = StyleSheet.create({})
-export default PeopleListScreen
\ No newline at end of file
+export default PeopleListScreen
diff --git a/MobileApp/src/components/screens/person-avatar.js b/MobileApp/src/components/screens/person-avatar.js
new file mode 100644
index 0000000..8a0b237
--- /dev/null
+++ b/MobileApp/src/components/screens/person-avatar.js
@@ -0,0 +1,10 @@
+import React, { Component } from 'react'
+import PersonAvatar from '../people/person-avatar'
+
+class PersonAvatarScreen extends Component {
+ render() {
+ return
+ }
+}
+
+export default PersonAvatarScreen
diff --git a/MobileApp/src/stores/entities-store.js b/MobileApp/src/stores/entities-store.js
index c7d100d..4706aad 100644
--- a/MobileApp/src/stores/entities-store.js
+++ b/MobileApp/src/stores/entities-store.js
@@ -1,34 +1,64 @@
-import {observable, computed, action} from 'mobx'
+import { observable, computed, action } from 'mobx'
import BasicStore from './basic-store'
import firebase from 'firebase/app'
-import {entitiesFromFB} from './utils'
+import { entitiesFromFB } from './utils'
class EntitiesStore extends BasicStore {
- @observable loading = false
- @observable loaded = false
+ @observable loading = false
+ @observable loaded = false
- @observable entities = {}
+ @observable entities = {}
- @computed get list() {
- return Object.values(this.entities)
- }
+ @computed
+ get list() {
+ return Object.values(this.entities)
+ }
- @computed get size() {
- return Object.keys(this.entities).length
- }
+ @computed
+ get size() {
+ return Object.keys(this.entities).length
+ }
}
export function loadAllHelper(refName) {
- return action(function () {
- this.loading = true
-
- firebase.database().ref(refName)
- .once('value', action(data => {
- this.entities = entitiesFromFB(data.val())
- this.loading = false
- this.loaded = true
- }))
+ return action(function() {
+ this.loading = true
+
+ firebase
+ .database()
+ .ref(refName)
+ .once(
+ 'value',
+ action((data) => {
+ this.entities = entitiesFromFB(data.val())
+ this.loading = false
+ this.loaded = true
+ })
+ )
+ })
+}
+
+export function subscribeHelper(refName) {
+ return action(function() {
+ this.loading = true
+
+ const callback = action((data) => {
+ this.entities = entitiesFromFB(data.val())
+ this.loading = false
+ this.loaded = true
})
+
+ firebase
+ .database()
+ .ref(refName)
+ .on('value', callback)
+
+ return () =>
+ firebase
+ .database()
+ .ref(refName)
+ .off('value', callback)
+ })
}
-export default EntitiesStore
\ No newline at end of file
+export default EntitiesStore
diff --git a/MobileApp/src/stores/people.js b/MobileApp/src/stores/people.js
index c1877f6..b20a404 100644
--- a/MobileApp/src/stores/people.js
+++ b/MobileApp/src/stores/people.js
@@ -1,18 +1,37 @@
-import EntitiesStore, {loadAllHelper} from './entities-store'
-import {computed, action} from 'mobx'
+import EntitiesStore, { subscribeHelper } from './entities-store'
+import { computed, action } from 'mobx'
import groupBy from 'lodash/groupBy'
+import firebase from 'firebase/app'
+import { decode } from 'base64-arraybuffer'
class PeopleStore extends EntitiesStore {
- @computed get sections() {
- const grouped = groupBy(this.list, person => person.firstName.charAt(0))
+ @computed
+ get sections() {
+ const grouped = groupBy(this.list, (person) => person.firstName.charAt(0))
- return Object.entries(grouped).map(([letter, list]) => ({
- title: `${letter}, ${list.length} people`,
- data: list.map(person => ({key: person.uid, person}))
- }))
- }
+ return Object.entries(grouped).map(([letter, list]) => ({
+ title: `${letter}, ${list.length} people`,
+ data: list.map((person) => ({ key: person.uid, person }))
+ }))
+ }
- @action loadAll = loadAllHelper('people')
+ @action loadAll = subscribeHelper('people')
+
+ async saveAvatar(uid, { base64 }) {
+ const ref = firebase.storage().ref(`people/${uid}/avatar.jpg`)
+
+ await ref.put(decode(base64))
+ const avatar = await ref.getDownloadURL()
+
+ this.updatePerson(uid, { avatar })
+ }
+
+ @action
+ updatePerson = (uid, data) =>
+ firebase
+ .database()
+ .ref(`people/${uid}`)
+ .update(data)
}
-export default PeopleStore
\ No newline at end of file
+export default PeopleStore
diff --git a/MobileApp/yarn.lock b/MobileApp/yarn.lock
index 00d582a..02f5e65 100644
--- a/MobileApp/yarn.lock
+++ b/MobileApp/yarn.lock
@@ -1750,6 +1750,10 @@ balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+base64-arraybuffer@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
+
base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"