Skip to content

Commit fde5d40

Browse files
committed
both: updated missing parts
1 parent 9f0c589 commit fde5d40

File tree

13 files changed

+121
-204
lines changed

13 files changed

+121
-204
lines changed

app/App.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from 'react';
2-
import { ScreenNavigator } from './src/screens/ScreenNavigator'
1+
import React from 'react'
2+
import { MainNavigator } from './src/screens/MainNavigator'
33
import { StyleSheet, View, Text, ActivityIndicator } from 'react-native'
44
import { useConnection } from './src/hooks/useConnection'
55

@@ -11,7 +11,7 @@ export default function App () {
1111
return (
1212
<View style={styles.container}>
1313
<ActivityIndicator />
14-
<Text>Connecting to our server...</Text>
14+
<Text>Connecting to our servers...</Text>
1515
</View>
1616
)
1717
}
@@ -26,7 +26,7 @@ export default function App () {
2626
)
2727
}
2828

29-
return (<ScreenNavigator/>);
29+
return (<MainNavigator />)
3030
}
3131

3232
const styles = StyleSheet.create({
@@ -36,4 +36,4 @@ const styles = StyleSheet.create({
3636
alignItems: 'center',
3737
justifyContent: 'center'
3838
}
39-
});
39+
})

app/babel.config.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
module.exports = function(api) {
2-
api.cache(true);
1+
module.exports = function (api) {
2+
api.cache(true)
33
return {
44
presets: ['babel-preset-expo'],
5-
plugins: ["module:react-native-dotenv"]
6-
};
7-
};
5+
plugins: ['module:react-native-dotenv']
6+
}
7+
}

app/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { registerRootComponent } from 'expo';
1+
import { registerRootComponent } from 'expo'
22

3-
import App from './App';
3+
import App from './App'
44

55
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
66
// It also ensures that whether you load the app in Expo Go or in a native build,
77
// the environment is set up appropriately
8-
registerRootComponent(App);
8+
registerRootComponent(App)

app/metro.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Learn more https://docs.expo.io/guides/customizing-metro
2-
const { getDefaultConfig } = require('expo/metro-config');
2+
const { getDefaultConfig } = require('expo/metro-config')
33

4-
module.exports = getDefaultConfig(__dirname);
4+
module.exports = getDefaultConfig(__dirname)

app/src/components/MyTasks.js

Lines changed: 11 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,11 @@
1-
import React, { useState } from 'react'
2-
import Meteor, { Mongo } from '@meteorrn/core'
3-
import { Button, Text, TextInput, View, StyleSheet } from 'react-native'
4-
import { inputStyles } from '../styles/inputStyles'
5-
6-
const Tasks = new Mongo.Collection('tasks')
7-
8-
export const MyTasks = (props) => {
9-
const [newTask, setNewTask] = useState('')
10-
const { tasks, isLoading } = Meteor.useTracker(() => {
11-
const sub = Meteor.subscribe('myTasks')
12-
13-
if (props.signedOut) {
14-
sub.stop()
15-
return { tasks: []}
16-
}
17-
18-
if (!sub.ready()) {
19-
return { tasks: [], isLoading: true }
20-
}
21-
22-
const tasks = Tasks.find({}, { sort: { createdAt: -1 } }).fetch();
23-
return { tasks, isLoading: false }
24-
});
25-
26-
// add loading message
27-
if (isLoading) {
28-
return (
29-
<View style={{ alignItems: 'center' }}>
30-
<Text>Loading tasks...</Text>
31-
</View>
32-
)
33-
}
34-
// add task
35-
const addTask = () => {
36-
Meteor.call('saveTask', { title: newTask, checked: false }, (err, res) => {
37-
if (err) {
38-
return console.error(err)
39-
}
40-
setNewTask('')
41-
})
42-
}
43-
const checkTask = ({ _id }) => {
44-
Meteor.call('saveTask', { _id, checked: true }, (err, res) => {
45-
if (err) {
46-
return console.error(err)
47-
}
48-
})
49-
}
50-
51-
// add task
52-
const renderTaskForm = () => {
53-
return (
54-
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
55-
<TextInput
56-
style={{ ...inputStyles.text, flex: 1, flewGrow: 1 }}
57-
placeholderTextColor="#8a8a8a"
58-
value={newTask}
59-
onChangeText={setNewTask}
60-
placeholder="What do you need to remember?"/>
61-
<Button disabled={newTask.length === 0} title="add" onPress={addTask}/>
62-
</View>
63-
)
64-
}
65-
66-
// no tasks yet
67-
if (tasks.length === 0) {
68-
return (
69-
<View style={{ alignItems: 'center' }}>
70-
<Text>No tasks yet</Text>
71-
{renderTaskForm()}
72-
</View>
73-
)
74-
}
75-
76-
const renderTasks = () => tasks.map((doc) => {
77-
return (
78-
<View key={doc._id} style={{ flexDirection: 'row', alignItems: 'center' }}>
79-
<Text style={doc.checked ? styles.checked : styles.unchecked}>{doc.title}</Text>
80-
<Button disabled={doc.checked} title="check" onPress={() => checkTask(doc)}/>
81-
</View>
82-
)
83-
})
84-
85-
return (
86-
<View style={{ alignItems: 'center', padding: 25 }}>
87-
{renderTasks()}
88-
{renderTaskForm()}
89-
</View>
90-
)
91-
}
92-
93-
const styles = StyleSheet.create({
94-
checked: {
95-
textDecorationLine: 'line-through',
96-
textDecorationStyle: 'solid',
97-
flex: 1,
98-
flexGrow: 1
99-
},
100-
unchecked: {
101-
fontWeight: 'bold',
102-
flex: 1,
103-
flexGrow: 1
104-
}
105-
})
1+
import React from 'react'
2+
import { Text } from 'react-native'
3+
4+
/**
5+
* Here you can implement the logic to subscribe to your tasks and CRUD them.
6+
* See: https://github.com/meteorrn/sample
7+
* @param props
8+
* @returns {JSX.Element}
9+
* @constructor
10+
*/
11+
export const MyTasks = () => (<Text>My Tasks not yet implemented</Text>)

app/src/contexts/AuthContext.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { createContext } from 'react'
22

33
/**
4-
* Our authentication context
4+
* Our authentication context provides an API for our components
5+
* that allows them to communicate with the servers in a decoupled way.
56
* @method signIn
67
* @method signUp
78
* @method signOut
8-
* @type {React.Context<unknown>}
9+
* @type {React.Context<object>}
910
*/
1011
export const AuthContext = createContext()

app/src/hooks/useConnection.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import Meteor from '@meteorrn/core'
33
import * as SecureStore from 'expo-secure-store'
44
import config from '../../config.json'
55

6-
// get detailed debug about internals
6+
// get detailed info about internals
77
Meteor.isVerbose = true
88

99
// connect with Meteor and use a secure store
10-
// to persist our received login token
10+
// to persist our received login token, so it's encrypted
11+
// and only readable for this very app
12+
// read more at: https://docs.expo.dev/versions/latest/sdk/securestore/
1113
Meteor.connect(config.backend.url, {
1214
AsyncStorage: {
1315
getItem: SecureStore.getItemAsync,
@@ -24,36 +26,34 @@ export const useConnection = () => {
2426
const [connected, setConnected] = useState(null)
2527
const [connectionError, setConnectionError] = useState(null)
2628

29+
// we use separate functions as the handlers, so they get removed
30+
// on unmount, which happens on auto-reload and would cause errors
31+
// if not handled
2732
useEffect(() => {
28-
// on any connection error
2933
const onError = (e) => setConnectionError(e)
3034
Meteor.ddp.on('error', onError)
3135

32-
// if a connection has been established
33-
const onConnected = () => {
34-
if (connected !== true) {
35-
setConnected(true)
36-
}
37-
}
36+
const onConnected = () => connected !== true && setConnected(true)
3837
Meteor.ddp.on('connected', onConnected)
3938

40-
// if the connection is lost
39+
// if the connection is lost, we not only switch the state
40+
// but also force to reconnect to the server
4141
const onDisconnected = () => {
4242
Meteor.ddp.autoConnect = true
4343
if (connected !== false) {
4444
setConnected(false)
4545
}
4646
Meteor.reconnect()
4747
}
48-
Meteor.ddp.on('disconnected',onDisconnected)
48+
Meteor.ddp.on('disconnected', onDisconnected)
4949

50-
// remove on unmount
50+
// remove all of these listeners on unmount
5151
return () => {
5252
Meteor.ddp.off('error', onError)
5353
Meteor.ddp.off('connected', onConnected)
54-
Meteor.ddp.off('disconnected',onDisconnected)
54+
Meteor.ddp.off('disconnected', onDisconnected)
5555
}
5656
}, [])
5757

5858
return { connected, connectionError }
59-
}
59+
}

app/src/hooks/useLogin.js

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
import React, { useReducer, useEffect, useMemo } from 'react';
1+
import { useReducer, useEffect, useMemo } from 'react'
22
import Meteor from '@meteorrn/core'
33

4+
/** @private */
45
const initialState = {
56
isLoading: true,
67
isSignout: false,
78
userToken: null
89
}
910

10-
/**
11-
* Manages our authentication state, that can consist of
12-
*
13-
* {{
14-
* userToken: string|null,
15-
* isLoading: boolean,
16-
* isSignOut: boolean|undefined
17-
* }}
18-
*/
11+
/** @private */
1912
const reducer = (state, action) => {
2013
switch (action.type) {
2114
case 'RESTORE_TOKEN':
@@ -39,8 +32,33 @@ const reducer = (state, action) => {
3932
}
4033
}
4134

35+
/** @private */
4236
const Data = Meteor.getData()
4337

38+
/**
39+
* Provides a state and authentication context for components to decide, whether
40+
* the user is authenticated and also to run several authentication actions.
41+
*
42+
* The returned state contains the following structure:
43+
* {{
44+
* isLoading: boolean,
45+
* isSignout: boolean,
46+
* userToken: string|null
47+
* }
48+
* }}
49+
*
50+
* the authcontext provides the following methods:
51+
* {{
52+
* signIn: function,
53+
* signOut: function,
54+
* signUp: function
55+
* }}
56+
*
57+
* @returns {{
58+
* state:object,
59+
* authContext: object
60+
* }}
61+
*/
4462
export const useLogin = () => {
4563
const [state, dispatch] = useReducer(reducer, initialState, undefined)
4664

@@ -80,11 +98,10 @@ export const useLogin = () => {
8098
},
8199
signUp: ({ email, password, onError }) => {
82100
Meteor.call('register', { email, password }, (err, res) => {
83-
console.debug('on register', err, res)
84101
if (err) {
85102
return onError(err)
86103
}
87-
// TODO make dry
104+
// TODO move the below code and the code from signIn into an own function
88105
Meteor.loginWithPassword(email, password, async (err) => {
89106
if (err) {
90107
if (err.message === 'Match failed [400]') {
@@ -101,4 +118,4 @@ export const useLogin = () => {
101118
}), [])
102119

103120
return { state, authContext }
104-
}
121+
}

app/src/screens/HomeScreen.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,17 @@ export const HomeScreen = () => {
1212
const renderError = () => {
1313
if (!error) { return null }
1414
return (
15-
<View style={{alignItems: 'center'}}>
15+
<View style={{ alignItems: 'center' }}>
1616
<Text>{error.message}</Text>
1717
</View>
1818
)
1919
}
2020

2121
return (
2222
<View style={styles.container}>
23-
<Text>My Tasks</Text>
2423
<MyTasks />
2524
{renderError()}
26-
<Button title="Sign out" onPress={handleSignOut} />
25+
<Button title='Sign out' onPress={handleSignOut} />
2726
</View>
2827
)
2928
}
@@ -35,4 +34,4 @@ const styles = StyleSheet.create({
3534
alignItems: 'center',
3635
justifyContent: 'center'
3736
}
38-
})
37+
})

0 commit comments

Comments
 (0)