Skip to content

Commit

Permalink
both: updated missing parts
Browse files Browse the repository at this point in the history
  • Loading branch information
jankapunkt committed Oct 13, 2022
1 parent 9f0c589 commit fde5d40
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 204 deletions.
10 changes: 5 additions & 5 deletions app/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { ScreenNavigator } from './src/screens/ScreenNavigator'
import React from 'react'
import { MainNavigator } from './src/screens/MainNavigator'
import { StyleSheet, View, Text, ActivityIndicator } from 'react-native'
import { useConnection } from './src/hooks/useConnection'

Expand All @@ -11,7 +11,7 @@ export default function App () {
return (
<View style={styles.container}>
<ActivityIndicator />
<Text>Connecting to our server...</Text>
<Text>Connecting to our servers...</Text>
</View>
)
}
Expand All @@ -26,7 +26,7 @@ export default function App () {
)
}

return (<ScreenNavigator/>);
return (<MainNavigator />)
}

const styles = StyleSheet.create({
Expand All @@ -36,4 +36,4 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center'
}
});
})
10 changes: 5 additions & 5 deletions app/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = function(api) {
api.cache(true);
module.exports = function (api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: ["module:react-native-dotenv"]
};
};
plugins: ['module:react-native-dotenv']
}
}
6 changes: 3 additions & 3 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { registerRootComponent } from 'expo';
import { registerRootComponent } from 'expo'

import App from './App';
import App from './App'

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
registerRootComponent(App)
4 changes: 2 additions & 2 deletions app/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
const { getDefaultConfig } = require('expo/metro-config')

module.exports = getDefaultConfig(__dirname);
module.exports = getDefaultConfig(__dirname)
116 changes: 11 additions & 105 deletions app/src/components/MyTasks.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,11 @@
import React, { useState } from 'react'
import Meteor, { Mongo } from '@meteorrn/core'
import { Button, Text, TextInput, View, StyleSheet } from 'react-native'
import { inputStyles } from '../styles/inputStyles'

const Tasks = new Mongo.Collection('tasks')

export const MyTasks = (props) => {
const [newTask, setNewTask] = useState('')
const { tasks, isLoading } = Meteor.useTracker(() => {
const sub = Meteor.subscribe('myTasks')

if (props.signedOut) {
sub.stop()
return { tasks: []}
}

if (!sub.ready()) {
return { tasks: [], isLoading: true }
}

const tasks = Tasks.find({}, { sort: { createdAt: -1 } }).fetch();
return { tasks, isLoading: false }
});

// add loading message
if (isLoading) {
return (
<View style={{ alignItems: 'center' }}>
<Text>Loading tasks...</Text>
</View>
)
}
// add task
const addTask = () => {
Meteor.call('saveTask', { title: newTask, checked: false }, (err, res) => {
if (err) {
return console.error(err)
}
setNewTask('')
})
}
const checkTask = ({ _id }) => {
Meteor.call('saveTask', { _id, checked: true }, (err, res) => {
if (err) {
return console.error(err)
}
})
}

// add task
const renderTaskForm = () => {
return (
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<TextInput
style={{ ...inputStyles.text, flex: 1, flewGrow: 1 }}
placeholderTextColor="#8a8a8a"
value={newTask}
onChangeText={setNewTask}
placeholder="What do you need to remember?"/>
<Button disabled={newTask.length === 0} title="add" onPress={addTask}/>
</View>
)
}

// no tasks yet
if (tasks.length === 0) {
return (
<View style={{ alignItems: 'center' }}>
<Text>No tasks yet</Text>
{renderTaskForm()}
</View>
)
}

const renderTasks = () => tasks.map((doc) => {
return (
<View key={doc._id} style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={doc.checked ? styles.checked : styles.unchecked}>{doc.title}</Text>
<Button disabled={doc.checked} title="check" onPress={() => checkTask(doc)}/>
</View>
)
})

return (
<View style={{ alignItems: 'center', padding: 25 }}>
{renderTasks()}
{renderTaskForm()}
</View>
)
}

const styles = StyleSheet.create({
checked: {
textDecorationLine: 'line-through',
textDecorationStyle: 'solid',
flex: 1,
flexGrow: 1
},
unchecked: {
fontWeight: 'bold',
flex: 1,
flexGrow: 1
}
})
import React from 'react'
import { Text } from 'react-native'

/**
* Here you can implement the logic to subscribe to your tasks and CRUD them.
* See: https://github.com/meteorrn/sample
* @param props
* @returns {JSX.Element}
* @constructor
*/
export const MyTasks = () => (<Text>My Tasks not yet implemented</Text>)
5 changes: 3 additions & 2 deletions app/src/contexts/AuthContext.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { createContext } from 'react'

/**
* Our authentication context
* Our authentication context provides an API for our components
* that allows them to communicate with the servers in a decoupled way.
* @method signIn
* @method signUp
* @method signOut
* @type {React.Context<unknown>}
* @type {React.Context<object>}
*/
export const AuthContext = createContext()
28 changes: 14 additions & 14 deletions app/src/hooks/useConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import Meteor from '@meteorrn/core'
import * as SecureStore from 'expo-secure-store'
import config from '../../config.json'

// get detailed debug about internals
// get detailed info about internals
Meteor.isVerbose = true

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

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

// if a connection has been established
const onConnected = () => {
if (connected !== true) {
setConnected(true)
}
}
const onConnected = () => connected !== true && setConnected(true)
Meteor.ddp.on('connected', onConnected)

// if the connection is lost
// if the connection is lost, we not only switch the state
// but also force to reconnect to the server
const onDisconnected = () => {
Meteor.ddp.autoConnect = true
if (connected !== false) {
setConnected(false)
}
Meteor.reconnect()
}
Meteor.ddp.on('disconnected',onDisconnected)
Meteor.ddp.on('disconnected', onDisconnected)

// remove on unmount
// remove all of these listeners on unmount
return () => {
Meteor.ddp.off('error', onError)
Meteor.ddp.off('connected', onConnected)
Meteor.ddp.off('disconnected',onDisconnected)
Meteor.ddp.off('disconnected', onDisconnected)
}
}, [])

return { connected, connectionError }
}
}
43 changes: 30 additions & 13 deletions app/src/hooks/useLogin.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import React, { useReducer, useEffect, useMemo } from 'react';
import { useReducer, useEffect, useMemo } from 'react'
import Meteor from '@meteorrn/core'

/** @private */
const initialState = {
isLoading: true,
isSignout: false,
userToken: null
}

/**
* Manages our authentication state, that can consist of
*
* {{
* userToken: string|null,
* isLoading: boolean,
* isSignOut: boolean|undefined
* }}
*/
/** @private */
const reducer = (state, action) => {
switch (action.type) {
case 'RESTORE_TOKEN':
Expand All @@ -39,8 +32,33 @@ const reducer = (state, action) => {
}
}

/** @private */
const Data = Meteor.getData()

/**
* Provides a state and authentication context for components to decide, whether
* the user is authenticated and also to run several authentication actions.
*
* The returned state contains the following structure:
* {{
* isLoading: boolean,
* isSignout: boolean,
* userToken: string|null
* }
* }}
*
* the authcontext provides the following methods:
* {{
* signIn: function,
* signOut: function,
* signUp: function
* }}
*
* @returns {{
* state:object,
* authContext: object
* }}
*/
export const useLogin = () => {
const [state, dispatch] = useReducer(reducer, initialState, undefined)

Expand Down Expand Up @@ -80,11 +98,10 @@ export const useLogin = () => {
},
signUp: ({ email, password, onError }) => {
Meteor.call('register', { email, password }, (err, res) => {
console.debug('on register', err, res)
if (err) {
return onError(err)
}
// TODO make dry
// TODO move the below code and the code from signIn into an own function
Meteor.loginWithPassword(email, password, async (err) => {
if (err) {
if (err.message === 'Match failed [400]') {
Expand All @@ -101,4 +118,4 @@ export const useLogin = () => {
}), [])

return { state, authContext }
}
}
7 changes: 3 additions & 4 deletions app/src/screens/HomeScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ export const HomeScreen = () => {
const renderError = () => {
if (!error) { return null }
return (
<View style={{alignItems: 'center'}}>
<View style={{ alignItems: 'center' }}>
<Text>{error.message}</Text>
</View>
)
}

return (
<View style={styles.container}>
<Text>My Tasks</Text>
<MyTasks />
{renderError()}
<Button title="Sign out" onPress={handleSignOut} />
<Button title='Sign out' onPress={handleSignOut} />
</View>
)
}
Expand All @@ -35,4 +34,4 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center'
}
})
})
Loading

0 comments on commit fde5d40

Please sign in to comment.