merge
|
@ -115,9 +115,20 @@ android {
|
|||
universalApk false // If true, also generate a universal APK
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
|
||||
storeFile file(MYAPP_RELEASE_STORE_FILE)
|
||||
storePassword MYAPP_RELEASE_STORE_PASSWORD
|
||||
keyAlias MYAPP_RELEASE_KEY_ALIAS
|
||||
keyPassword MYAPP_RELEASE_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
|
@ -1,3 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">app</string>
|
||||
<string name="app_name">ENEI 2019</string>
|
||||
</resources>
|
||||
|
|
After Width: | Height: | Size: 42 KiB |
|
@ -18,3 +18,8 @@
|
|||
# org.gradle.parallel=true
|
||||
|
||||
android.enableAapt2=false
|
||||
|
||||
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
|
||||
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
|
||||
MYAPP_RELEASE_STORE_PASSWORD=aspire98H
|
||||
MYAPP_RELEASE_KEY_PASSWORD=aspire98H
|
352
App/app/App.js
|
@ -1,54 +1,46 @@
|
|||
/**
|
||||
* Enei 2019 React Native App
|
||||
*
|
||||
* João Borges
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import Icon from 'react-native-vector-icons/AntDesign';
|
||||
import AppIntroSlider from 'react-native-app-intro-slider'
|
||||
import {Platform, StyleSheet, Text, View, StatusBar,Dimensions,Image,ActivityIndicator} from 'react-native';
|
||||
|
||||
import {Platform, StyleSheet, Text, View, StatusBar} from 'react-native';
|
||||
import deviceStorage from '././services/deviceStorage'
|
||||
import {bindActionCreators} from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import QRCodeScanner from 'react-native-qrcode-scanner';
|
||||
import {UtilStyles} from './assets/styles'
|
||||
import * as Actions from './actions'; //Import your actions
|
||||
import {RkButton,
|
||||
RkTheme , RkText} from 'react-native-ui-kitten';
|
||||
|
||||
import Router from './Router'
|
||||
import Login from './screens/Login'
|
||||
import {AsyncStorage, ActivityIndicator} from 'react-native';
|
||||
import AuthLoadingScreen from "./screens/AuthLoading";
|
||||
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import reducer from './reducers';
|
||||
import { AppRegistry } from 'react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import { compose, createStore, combineReducers, applyMiddleware} from 'redux';
|
||||
const loggerMiddleware = createLogger({ predicate: (getState, action) => __DEV__ });
|
||||
const SCREEN_HEIGHT = Dimensions.get("window").height;
|
||||
const SCREEN_WIDTH = Dimensions.get("window").width;
|
||||
|
||||
|
||||
function configureStore(initialState) {
|
||||
const enhancer = compose(
|
||||
applyMiddleware(
|
||||
thunkMiddleware, // used to dispatch() functions
|
||||
loggerMiddleware, // used for logging actions
|
||||
),
|
||||
);
|
||||
return createStore(reducer, initialState, enhancer);
|
||||
}
|
||||
|
||||
|
||||
const store = configureStore({});
|
||||
export default class App extends Component {
|
||||
class App extends Component {
|
||||
|
||||
constructor(props) {
|
||||
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
firstLogin: null,
|
||||
jwt: '',
|
||||
loading: true
|
||||
|
||||
token:false,
|
||||
tokenData:'',
|
||||
loggedIn:false,
|
||||
onHold:true
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
//verifica se o utilizador tem token guardado
|
||||
this.props.checkUser();
|
||||
console.log('logged:'+this.props.loggedIn);
|
||||
}
|
||||
|
||||
newJWT(jwt) {
|
||||
|
@ -56,161 +48,185 @@ export default class App extends Component {
|
|||
jwt: jwt
|
||||
});
|
||||
}
|
||||
|
||||
//componentDidMount() is invoked immediately after a component is mounted
|
||||
/*componentDidMount() {
|
||||
onSuccess = (e) => {
|
||||
|
||||
|
||||
AsyncStorage.removeItem('firstLogin');
|
||||
|
||||
AsyncStorage.getItem('firstLogin').then((value) => {
|
||||
|
||||
console.log('aqui')
|
||||
if (value == null) {
|
||||
//setItem (key: string, value: string)
|
||||
deviceStorage.saveItem('firstLogin', JSON.stringify(true));
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
//this.setState({firstLogin: false});
|
||||
}
|
||||
|
||||
this.setState({loading: false});
|
||||
|
||||
})
|
||||
}*/
|
||||
|
||||
|
||||
//Buttons do Intro Slider
|
||||
_renderNextButton = () => {
|
||||
return (
|
||||
<View style={styles.buttonCircle}>
|
||||
<Icon
|
||||
name='right'
|
||||
color='rgba(255, 255, 255, .9)'
|
||||
size={24}
|
||||
style={{backgroundColor: 'transparent'}}/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
_renderDoneButton = () => {
|
||||
return (
|
||||
<View style={styles.buttonCircle}>
|
||||
<Icon
|
||||
name='check'
|
||||
color='rgba(255, 255, 255, .9)'
|
||||
size={24}
|
||||
style={{backgroundColor: 'transparent'}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
this.props.login(e.data,'80f3b6e5');
|
||||
|
||||
};
|
||||
|
||||
//--Buttons do Intro Slider
|
||||
|
||||
render() {
|
||||
|
||||
|
||||
|
||||
if(this.props.onHold){
|
||||
return (
|
||||
|
||||
<Provider store={store}>
|
||||
<Router />
|
||||
</Provider>
|
||||
<ActivityIndicator size="large" color="#0000ff" />
|
||||
)
|
||||
|
||||
|
||||
/* if (this.state.loading) {
|
||||
}
|
||||
else {
|
||||
|
||||
if (this.state.firstLaunch) {
|
||||
console.log('token... '+ this.props.token)
|
||||
|
||||
//se existir token
|
||||
|
||||
|
||||
if(this.props.token == true){
|
||||
|
||||
return (
|
||||
<AppIntroSlider
|
||||
slides={slides}
|
||||
renderDoneButton={this._renderDoneButton}
|
||||
renderNextButton={this._renderNextButton}
|
||||
onDone={() => this.setState({firstLaunch: false})}
|
||||
|
||||
<Router></Router>
|
||||
|
||||
)
|
||||
|
||||
}else{
|
||||
|
||||
//se não existir vai para o ecrã de scan QR
|
||||
return (
|
||||
|
||||
|
||||
<QRCodeScanner
|
||||
|
||||
showMarker
|
||||
|
||||
onRead={this.onSuccess.bind(this)}
|
||||
cameraStyle={{ height: SCREEN_HEIGHT }}
|
||||
|
||||
customMarker={
|
||||
|
||||
<View style={styles.rectangleContainer}>
|
||||
<View style={styles.logo}>
|
||||
<Image style={UtilStyles.loginImage}
|
||||
source={require('./assets/img/logo.png')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
else if (!this.state.firstLaunch && !this.state.jwt) { //&& !this.state.jwt}
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<Login/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
else { // !this.state.firstLaunch && this.state.jwt
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<Routes />
|
||||
|
||||
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<View style={styles.leftAndRightOverlay}>
|
||||
</View>
|
||||
|
||||
<View style={styles.rectangle}>
|
||||
|
||||
</View>
|
||||
|
||||
|
||||
<View style={styles.leftAndRightOverlay}>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.bottomOverlay}>
|
||||
|
||||
<View style={{flex:1, alignItems: 'center', alignContent: 'center'}}>
|
||||
|
||||
<RkText rkType='primary' style={styles.recover}>Recuperar pin de acesso</RkText>
|
||||
<RkButton rkType='dark' style={styles.manual}>lols</RkButton>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}*/
|
||||
}
|
||||
/>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
//Styles
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
RkTheme.setType('RkButton', 'dark', {
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
paddingTop:10,
|
||||
backgroundColor: 'gray',
|
||||
|
||||
buttonCircle: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
backgroundColor: 'rgba(0, 0, 0, .2)',
|
||||
borderRadius: 20,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
image: {
|
||||
width: 320,
|
||||
height: 320,
|
||||
borderRadius: 90,
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//Introducing Slides
|
||||
const slides = [
|
||||
{
|
||||
key: 'somethun',
|
||||
title: 'Welcome ENEI\'19',
|
||||
text: 'Description.\nSay something cool',
|
||||
image: {
|
||||
uri: 'http://aboutreact.com/wp-content/uploads/2018/08/mobile_recharge.png'
|
||||
},
|
||||
imageStyle: styles.image,
|
||||
backgroundColor: '#59b2ab',
|
||||
},
|
||||
{
|
||||
key: 'somethun-dos',
|
||||
title: 'Title 2',
|
||||
text: 'Other cool stuff',
|
||||
image: //require('./assets/2.jpg'),
|
||||
{
|
||||
uri: 'http://aboutreact.com/wp-content/uploads/2018/08/flight_ticket_booking.png'
|
||||
},
|
||||
imageStyle: styles.image,
|
||||
backgroundColor: '#febe29',
|
||||
},
|
||||
{
|
||||
key: 'somethun1',
|
||||
title: 'Rocket guy',
|
||||
text: 'I\'m already out of descriptions\n\nLorem ipsum bla bla bla',
|
||||
image: {
|
||||
uri: 'http://aboutreact.com/wp-content/uploads/2018/08/best_deals1.png'
|
||||
},
|
||||
imageStyle: styles.image,
|
||||
backgroundColor: '#22bcb5',
|
||||
}
|
||||
];
|
||||
const rectDimensions = SCREEN_WIDTH * 0.85; // this is equivalent to 255 from a 393 device width
|
||||
|
||||
const overlayColor = 'rgba(0,0,0,0.30)';
|
||||
|
||||
const styles = {
|
||||
|
||||
recover:{
|
||||
paddingTop:10,
|
||||
color: "red",
|
||||
paddingBottom:10
|
||||
},
|
||||
manual:{
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
logo:{
|
||||
|
||||
height:SCREEN_HEIGHT*0.35,
|
||||
width:SCREEN_WIDTH,
|
||||
backgroundColor: overlayColor,
|
||||
},
|
||||
rectangleContainer: {
|
||||
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "transparent",
|
||||
|
||||
},
|
||||
|
||||
rectangle: {
|
||||
|
||||
height: rectDimensions,
|
||||
width: rectDimensions,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "transparent"
|
||||
},
|
||||
|
||||
topOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: overlayColor,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
},
|
||||
|
||||
bottomOverlay: {
|
||||
flex: 1,
|
||||
height: SCREEN_HEIGHT,
|
||||
width: SCREEN_WIDTH,
|
||||
backgroundColor: overlayColor,
|
||||
paddingBottom: SCREEN_WIDTH * 0.2
|
||||
},
|
||||
|
||||
leftAndRightOverlay: {
|
||||
height: rectDimensions,
|
||||
width: SCREEN_WIDTH,
|
||||
backgroundColor: overlayColor
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
function mapStateToProps(state, props) {
|
||||
|
||||
return {
|
||||
|
||||
token: state.apiReducer.token,
|
||||
tokenData:state.apiReducer.tokenData,
|
||||
loggedIn: state.apiReducer.loggedIn,
|
||||
onHold: state.apiReducer.onHold
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
|
||||
return bindActionCreators(Actions, dispatch);
|
||||
}
|
||||
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
export default function createReducer(initialState, handlers) {
|
||||
return function reducer(state = initialState, action) {
|
||||
if (handlers.hasOwnProperty(action.type)) {
|
||||
return handlers[action.type](state, action)
|
||||
} else {
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,20 +19,28 @@ import Social from './screens/Social'
|
|||
import Scan from './screens/Scan'
|
||||
|
||||
import Calendar from './screens/Calendar'
|
||||
import Home from './screens/Home'
|
||||
import logout from './screens/logout'
|
||||
|
||||
|
||||
|
||||
/*Icons*/
|
||||
import Icon from "react-native-vector-icons/Ionicons"
|
||||
|
||||
import IconF from "react-native-vector-icons/Foundation"
|
||||
import IconFA from "react-native-vector-icons/FontAwesome5"
|
||||
|
||||
|
||||
const AppStack = createBottomTabNavigator(
|
||||
{
|
||||
|
||||
|
||||
Calendar: {
|
||||
screen: Calendar,
|
||||
|
||||
navigationOptions: {
|
||||
|
||||
tabBarIcon: ({tintColor}) => (
|
||||
<Icon name="ios-beer" size={30}/>
|
||||
<IconF name="calendar" color={tintColor} size={30}/>
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -42,7 +50,7 @@ const AppStack = createBottomTabNavigator(
|
|||
navigationOptions: {
|
||||
|
||||
tabBarIcon: ({tintColor}) => (
|
||||
<Icon name="ios-mail" size={30}/>
|
||||
<Icon name="ios-mail" color={tintColor} size={30}/>
|
||||
)
|
||||
},
|
||||
},
|
||||
|
@ -50,38 +58,47 @@ const AppStack = createBottomTabNavigator(
|
|||
screen: Scan,
|
||||
|
||||
navigationOptions: {
|
||||
|
||||
tabBarIcon: ({tintColor}) => (
|
||||
<Icon name="ios-qr-scanner" size={30}/>
|
||||
)
|
||||
<Icon name="ios-qr-scanner" color={tintColor} size={45}/>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
Eventos: {
|
||||
screen: Eventos,
|
||||
|
||||
navigationOptions: {
|
||||
|
||||
tabBarIcon: ({tintColor}) => (
|
||||
<Icon name="ios-beer" size={30}/>
|
||||
<Icon name="ios-beer" color={tintColor} size={30}/>
|
||||
)
|
||||
},
|
||||
},
|
||||
|
||||
Home: {
|
||||
screen:Screens.Home,
|
||||
screen: Home,
|
||||
navigationOptions: {
|
||||
|
||||
tabBarIcon: ({tintColor}) => (
|
||||
<Icon name="md-person" size={30}/>
|
||||
<Icon name="md-home" color={tintColor} size={30}/>
|
||||
)
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
initialRouteName: 'Home',
|
||||
|
||||
},{
|
||||
initialRouteName : 'Home'
|
||||
tabBarOptions: {
|
||||
showLabel: false, // hide labels
|
||||
activeTintColor: '#858683', // active icon color
|
||||
inactiveTintColor: '#d8d6c9', // inactive icon color
|
||||
style: {
|
||||
backgroundColor: '#fff' // TabBar background
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const AuthStack = createStackNavigator(
|
||||
{
|
||||
|
@ -95,9 +112,33 @@ const AuthStack = createStackNavigator(
|
|||
headerVisible: false,
|
||||
}
|
||||
}*/
|
||||
|
||||
);
|
||||
|
||||
const Stack = createStackNavigator({
|
||||
tabs: {
|
||||
screen: AppStack,
|
||||
navigationOptions: ({navigation}) => {
|
||||
const index = navigation.state.index;
|
||||
|
||||
if (navigation.state.routes[index].routeName !== 'Scan') {
|
||||
return {
|
||||
headerTitle: `${navigation.state.routes[index].routeName}`,
|
||||
headerRight: (
|
||||
<TouchableOpacity style={{marginRight: 20}} onPress={() => navigation.navigate('Home')}>
|
||||
<IconFA name="user-edit" size={22}/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
header: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
export default createAppContainer(createSwitchNavigator(
|
||||
{
|
||||
|
@ -107,7 +148,7 @@ export default createAppContainer(createSwitchNavigator(
|
|||
|
||||
},
|
||||
{
|
||||
initialRouteName: 'AuthLoading'
|
||||
initialRouteName: 'App'
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
export const DATA_AVAILABLE = 'DATA_AVAILABLE';
|
||||
export const API_LOGIN = 'API_LOGIN';
|
||||
export const CHECK_USER='CHECK_USER';
|
||||
export const LOGOUT_USER= 'LOGOUT_USER';
|
||||
export const USER_INFO= 'USER_INFO'
|
||||
|
||||
import { AsyncStorage } from 'react-native';
|
||||
|
||||
|
||||
//Import the sample data
|
||||
import Data from '../intructions.json';
|
||||
import Login from '../screens/Login.js';
|
||||
|
||||
export function getData(){
|
||||
return (dispatch) => {
|
||||
|
||||
//Make API Call
|
||||
//For this example, I will be using the sample data in the json file
|
||||
//delay the retrieval [Sample reasons only]
|
||||
setTimeout(() => {
|
||||
const data = Data.instructions;
|
||||
dispatch({type: DATA_AVAILABLE, data:data});
|
||||
}, 2000);
|
||||
|
||||
};
|
||||
}
|
||||
const saveToken = async token => {
|
||||
try {
|
||||
|
||||
await AsyncStorage.setItem('userToken', token);
|
||||
|
||||
} catch (error) {
|
||||
// Error retrieving data
|
||||
console.log(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getToken = async () => {
|
||||
var tokem;
|
||||
try {
|
||||
token = await AsyncStorage.getItem('userToken') || 'none';
|
||||
} catch (error) {
|
||||
// Error retrieving data
|
||||
console.log(error.message);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
const deleteToken = async () => {
|
||||
try {
|
||||
await AsyncStorage.removeItem('userToken');
|
||||
} catch (error) {
|
||||
// Error retrieving data
|
||||
console.log(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function login(user, pass){
|
||||
|
||||
return (dispatch)=>{
|
||||
|
||||
console.log('user: ' +user + ' password: '+pass );
|
||||
var details = {
|
||||
'username': user,
|
||||
'password': pass,
|
||||
'grant_type': 'password'
|
||||
};
|
||||
|
||||
var formBody = [];
|
||||
for (var property in details) {
|
||||
var encodedKey = encodeURIComponent(property);
|
||||
var encodedValue = encodeURIComponent(details[property]);
|
||||
formBody.push(encodedKey + "=" + encodedValue);
|
||||
}
|
||||
formBody = formBody.join("&");
|
||||
|
||||
fetch('http://enei2019.uingress.com/internal/api/token', {
|
||||
|
||||
method: 'POST',
|
||||
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
|
||||
},
|
||||
body: formBody
|
||||
|
||||
}).catch(err=>{
|
||||
|
||||
console.log(err);
|
||||
alert("error");
|
||||
dispatch({
|
||||
type: API_LOGIN,
|
||||
loggedIn:false,
|
||||
tokenData:'error'
|
||||
});
|
||||
|
||||
}).then(res=>res.json()).then(parsed=>{
|
||||
|
||||
console.log('parsed'+parsed.access_token)
|
||||
|
||||
// deviceStorage.saveItem(parsed.access_token);
|
||||
try {
|
||||
|
||||
saveToken(parsed.access_token).then(a=>{
|
||||
console.log('sucess');
|
||||
}).catch(a=>{
|
||||
console.log('error saving')
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.log('Error saving token')
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: API_LOGIN,
|
||||
loggedIn:true,
|
||||
token:true,
|
||||
tokenData:parsed
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
).then(a=>{})
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserInfo(){
|
||||
return (dispatch)=>{
|
||||
getToken().then(a=>{
|
||||
|
||||
console.log('get user info');
|
||||
var token;
|
||||
var obj = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization':"Bearer "+a,
|
||||
},
|
||||
}
|
||||
|
||||
fetch('http://enei2019.uingress.com/internal/api/Attendee/Detail', obj)
|
||||
|
||||
.then(function(res) {
|
||||
|
||||
//console.log(res._bodyText);
|
||||
|
||||
var obj = JSON.parse(res._bodyText);
|
||||
|
||||
dispatch({
|
||||
type: USER_INFO,
|
||||
user: obj
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
.then(function(resJson) {
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function logoutUser(){
|
||||
return (dispatch)=>{
|
||||
|
||||
deleteToken().then(a=>{
|
||||
|
||||
console.log('token apagado');
|
||||
dispatch({
|
||||
type: LOGOUT_USER,
|
||||
loggedIn:false,
|
||||
tokenData:'error',
|
||||
token:false
|
||||
});
|
||||
}).catch(err=>{
|
||||
|
||||
console.log('errors');
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function checkUser(){
|
||||
return (dispatch)=>{
|
||||
|
||||
getToken().then(a=>{
|
||||
|
||||
console.log('sucess: '+a)
|
||||
|
||||
if(a=='none'){
|
||||
dispatch({type: CHECK_USER,token:false, tokenData:'error', });
|
||||
|
||||
}
|
||||
else{
|
||||
dispatch({type: CHECK_USER,token:true, tokenData:a,});
|
||||
}
|
||||
|
||||
|
||||
}).catch(a=>{
|
||||
console.log('erros');
|
||||
dispatch({type: CHECK_USER,token:false, tokenData:'error'});
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
import * as types from './types'
|
||||
import ReactNative from 'react-native'
|
||||
|
||||
export function setScreen(state) {
|
||||
return {
|
||||
type: types.SET_SCREEN,
|
||||
state
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
import * as types from './types'
|
||||
import ReactNative from 'react-native'
|
||||
|
||||
export function setScreen(state) {
|
||||
return {
|
||||
type: types.SET_SCREEN,
|
||||
state
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
// Posts
|
||||
export const SET_POST = 'SET_POST';
|
||||
|
||||
// Navigation
|
||||
export const SET_SCREEN = 'SET_SCREEN';
|
|
@ -1,82 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { ActionCreators } from '../actions';
|
||||
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableHighlight,
|
||||
} from 'react-native';
|
||||
|
||||
class AppContainer extends Component {
|
||||
|
||||
changeActiveScreen() {
|
||||
let screens = ['Home', 'About', 'Contact', 'Portfolio', 'News'];
|
||||
this.props.setScreen(screens[(Math.random() * screens.length) | 0]);
|
||||
}
|
||||
|
||||
changeCurrentPost() {
|
||||
let posts = ['Post 1', 'Post 2', 'Post 3', 'Post 4', 'Post 5', 'Post 6'];
|
||||
this.props.setPost(posts[(Math.random() * posts.length) | 0]);
|
||||
}
|
||||
|
||||
render() {
|
||||
let activeScreen = this.props.activeScreen;
|
||||
let currentPost = this.props.currentPost;
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<Text style={styles.welcomeText}>Hello World</Text>
|
||||
<Text style={styles.subHead}>The active screen is: {activeScreen.state}</Text>
|
||||
<Text style={styles.subHead}>The current post is: {currentPost.state}</Text>
|
||||
<TouchableHighlight style={styles.button} onPress={ () => { this.changeActiveScreen() } }>
|
||||
<Text style={styles.buttonText}>Change Active Screen State</Text>
|
||||
</TouchableHighlight>
|
||||
|
||||
<TouchableHighlight style={styles.button} onPress={ () => { this.changeCurrentPost() } }>
|
||||
<Text style={styles.buttonText}>Change Current Post State</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
padding: 50,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'green',
|
||||
marginBottom: 10,
|
||||
padding: 10,
|
||||
},
|
||||
buttonText: {
|
||||
color: 'white',
|
||||
textAlign: 'center',
|
||||
},
|
||||
welcomeText: {
|
||||
marginBottom: 30,
|
||||
fontSize: 40,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subHead: {
|
||||
textAlign: 'center',
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(ActionCreators, dispatch);
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
activeScreen: state.activeScreen,
|
||||
currentPost: state.currentPost,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AppContainer);
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"instructions": [
|
||||
{
|
||||
"title": "Create React Native Project",
|
||||
"description": "react-native init ReactReduxBoilerPlate"
|
||||
},
|
||||
{
|
||||
"title": "Install Dependencies",
|
||||
"description": "In your project root, run npm install --save react-redux \nnpm install —save redux \nnpm install —save redux-thunk"
|
||||
},
|
||||
{
|
||||
"title": "Create Folder Structure",
|
||||
"description": "In your project root create an 'app' folder. In the app folder create an 'actions' folder , a 'reducers' folder and a 'components' folder."
|
||||
},
|
||||
{
|
||||
"title": "Create your first action",
|
||||
"description": "The action is a basic function called from the component whenever we want the whole state of the app to be changed. Our action creator is a simple function returning an object (the action itself)with a type attribute expressing what happened with the app.\nIn your actions folder create a js file 'index.js'"
|
||||
},
|
||||
{
|
||||
"title": "Create your first reducer",
|
||||
"description": "Reducers are the ones in charge of updating the state of the app. Redux will automatically pass the current state of the app and the action occurred. It’s up to the reducer to realize if it needs to modify the state or not based on the action.type.\nIn your reducers folder create a js file 'index.js'"
|
||||
},
|
||||
{
|
||||
"title": "Create your component",
|
||||
"description": "In your components folder create a js file 'home.js'"
|
||||
},
|
||||
{
|
||||
"title": "Create Store",
|
||||
"description": "In the app folder, create a js file 'store.js'"
|
||||
},
|
||||
{
|
||||
"title": "Link it all together",
|
||||
"description": "Redux needs to inject a store holding the app state into the app. To do so, it requires a ‘Provider’ wrapping the whole app.In the app folder, create a js file 'setup.js'"
|
||||
},
|
||||
{
|
||||
"title": "Update your main files",
|
||||
"description": "Update index.ios.js and index.android.js"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,8 +1,61 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import * as NavigationReducers from './navigation';
|
||||
import * as PostsReducers from './posts';
|
||||
|
||||
export default combineReducers(Object.assign(
|
||||
NavigationReducers,
|
||||
PostsReducers,
|
||||
));
|
||||
import { DATA_AVAILABLE, API_LOGIN, CHECK_USER, LOGOUT_USER, USER_INFO } from "../actions/" //Import the actions types constant we defined in our actions
|
||||
|
||||
|
||||
let dataState = { data: [], loading:true ,token:true};
|
||||
|
||||
const dataReducer = (state = dataState, action) => {
|
||||
switch (action.type) {
|
||||
case DATA_AVAILABLE:
|
||||
state = Object.assign({}, state, { data: action.data, loading:false });
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
let apiState= {token:false, tokenData:'error', loggedIn:false, onHold:true, user:{}}
|
||||
|
||||
const apiReducer = (state = apiState, action) => {
|
||||
|
||||
switch(action.type){
|
||||
|
||||
case API_LOGIN:
|
||||
|
||||
state=Object.assign({},state, { loggedIn:action.loggedIn, tokenData:action.tokenData , token:action.token});
|
||||
return state;
|
||||
|
||||
case CHECK_USER:
|
||||
|
||||
state=Object.assign({},state, { token:action.token, tokenData:action.tokenData, onHold:false});
|
||||
|
||||
return state;
|
||||
|
||||
case LOGOUT_USER:
|
||||
|
||||
state=Object.assign({},state, { token:action.token, tokenData:action.tokenData, loggedIn:action.loggedIn});
|
||||
|
||||
return state;
|
||||
|
||||
case USER_INFO:
|
||||
|
||||
state=Object.assign({},state, { user: action.user });
|
||||
|
||||
return state;
|
||||
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Combine all the reducers
|
||||
const rootReducer = combineReducers({
|
||||
dataReducer, apiReducer
|
||||
// ,[ANOTHER REDUCER], [ANOTHER REDUCER] ....
|
||||
})
|
||||
|
||||
export default rootReducer;
|
|
@ -1,8 +0,0 @@
|
|||
import createReducer from '../Helpers/createReducer'
|
||||
import * as types from '../actions/types'
|
||||
|
||||
export const activeScreen = createReducer({}, {
|
||||
[types.SET_SCREEN](state, action) {
|
||||
return action;
|
||||
}
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
import createReducer from '../Helpers/createReducer'
|
||||
import * as types from '../actions/types'
|
||||
|
||||
export const currentPost = createReducer({}, {
|
||||
[types.SET_POST](state, action) {
|
||||
return action;
|
||||
}
|
||||
});
|
|
@ -1,63 +1,119 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Button, View, Text , TouchableOpacity} from 'react-native';
|
||||
import {RkButton,
|
||||
RkTheme } from 'react-native-ui-kitten';
|
||||
import { Button, View, Text , TouchableOpacity, FlatList, ActivityIndicator} from 'react-native';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import deviceStorage from '../services/deviceStorage';
|
||||
import AuthLoadingScreen from './AuthLoading';
|
||||
import api from '../services/api';
|
||||
import * as Actions from '../actions'; //Import your actionss
|
||||
|
||||
|
||||
import Counter from './Counter'
|
||||
import { createStore } from 'redux';
|
||||
import {Provider} from 'react-redux'
|
||||
class Home extends Component {
|
||||
|
||||
const initialState={
|
||||
constructor(props) {
|
||||
|
||||
counter:0
|
||||
}
|
||||
const reducer=(state =initialState, action)=>{
|
||||
super(props);
|
||||
|
||||
switch(action.type){
|
||||
|
||||
case 'INCREASE_COUNTER':
|
||||
return {
|
||||
counter: state.counter+1
|
||||
}
|
||||
|
||||
case 'DECREASE_COUNTER':
|
||||
return {
|
||||
counter: state.counter-1
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
const store = createStore(reducer);
|
||||
|
||||
|
||||
|
||||
export class Home extends Component {
|
||||
|
||||
static navigationOptions = {
|
||||
title: 'Home'
|
||||
this.state = {
|
||||
token:false,
|
||||
tokenData:'',
|
||||
loggedIn:false,
|
||||
onHold:true,
|
||||
user:{}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
//this.props.logoutUser();
|
||||
|
||||
this.props.getUserInfo();
|
||||
|
||||
console.log('logged:'+this.props.loggedIn);
|
||||
|
||||
console.log('there we go')
|
||||
|
||||
console.log(this.props.user)
|
||||
}
|
||||
|
||||
bClick(){
|
||||
|
||||
//this.props.logoutUser();
|
||||
|
||||
//var navigate = this.props.navigation.navigate
|
||||
}
|
||||
_logout = () => {
|
||||
console.log("asdasd");
|
||||
// this.props.navigation.navigate('scan');
|
||||
this.props.getUserInfo();
|
||||
// this.props.logout();
|
||||
this.props.logoutUser();
|
||||
}
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
if(this.props.token){
|
||||
|
||||
|
||||
console.log(this.props.user)
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<View style={{flex:1, alignItems: 'center', alignContent: 'center'}}>
|
||||
<Counter></Counter>
|
||||
<View >
|
||||
|
||||
|
||||
<Button onPress={this._logout} title="LOGOUT"/>
|
||||
<Text></Text>
|
||||
<Text>Nome: {this.props.user.Email}</Text>
|
||||
<Text>city: {this.props.user.City}</Text>
|
||||
<Text>phone: {this.props.user.Mobile}</Text>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</View>
|
||||
|
||||
</Provider>
|
||||
|
||||
);
|
||||
}
|
||||
else{
|
||||
return (
|
||||
<View >
|
||||
<Text>sem permissões para aceder aqui</Text>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
renderItem({item, index}) {
|
||||
return (
|
||||
<View>
|
||||
<Text >
|
||||
{(parseInt(index) + 1)}{". "}{item.title}
|
||||
</Text>
|
||||
<Text >
|
||||
{item.description}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function mapStateToProps(state, props) {
|
||||
|
||||
return {
|
||||
|
||||
|
||||
token: state.apiReducer.token,
|
||||
user: state.apiReducer.user
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
|
||||
return bindActionCreators(Actions, dispatch);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Home);
|
|
@ -12,13 +12,12 @@ import {RkButton,
|
|||
|
||||
export default class Scan extends React.Component {
|
||||
|
||||
|
||||
onSuccess = (e) => {
|
||||
|
||||
// console.log(e.data);
|
||||
|
||||
|
||||
console.log(e);
|
||||
console.log(e.data);
|
||||
|
||||
|
||||
|
||||
|
@ -38,6 +37,7 @@ export default class Scan extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<Text> Camera Loading....</Text>
|
||||
{ this.state.isRender &&
|
||||
<QRCodeScanner />
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Button, View, Text , TouchableOpacity, FlatList, ActivityIndicator} from 'react-native';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import * as Actions from '../actions'; //Import your actionss
|
||||
|
||||
|
||||
class logout extends Component {
|
||||
|
||||
constructor(props) {
|
||||
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
token:false,
|
||||
tokenData:'',
|
||||
loggedIn:false,
|
||||
onHold:true
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
console.log('logout')
|
||||
this.props.logoutUser();
|
||||
|
||||
//this.props.navigation.navigate('Home');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
const { navigate } = this.props.navigation;
|
||||
return (
|
||||
<View >
|
||||
|
||||
<Text>LOGGED OUT</Text>
|
||||
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function mapStateToProps(state, props) {
|
||||
|
||||
return {
|
||||
|
||||
|
||||
token: state.apiReducer.token,
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
|
||||
return bindActionCreators(Actions, dispatch);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(logout);
|
|
@ -0,0 +1,7 @@
|
|||
import { createStore, applyMiddleware } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import reducers from './reducers/index'; //Import the reducer
|
||||
|
||||
// Connect our store to the reducers
|
||||
export default createStore(reducers, applyMiddleware(thunk));
|
14
App/index.js
|
@ -2,10 +2,20 @@
|
|||
import React from 'react';
|
||||
import {AppRegistry} from 'react-native';
|
||||
import {Provider} from 'react-redux';
|
||||
import App from './app/App';
|
||||
|
||||
import {name as appName} from './app.json';
|
||||
|
||||
import store from './app/store'; //Import the store
|
||||
|
||||
|
||||
import App from './app/App' //Import the component file
|
||||
|
||||
const RNRedux = () => (
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
|
||||
AppRegistry.registerComponent(appName, () => RNRedux);
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
|
|
|
@ -6838,6 +6838,11 @@
|
|||
"resolved": "https://registry.npmjs.org/react-native-ionicons/-/react-native-ionicons-4.5.5.tgz",
|
||||
"integrity": "sha512-Pj1jFcwcOPG62EzWpLfu7UQwByd3SjTfjbs2WMPjmnfBuA6xiR8hh1+fflhpQ7Yv4j5cQuCSiR53uLbasxH/6Q=="
|
||||
},
|
||||
"react-native-loader": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-loader/-/react-native-loader-1.2.1.tgz",
|
||||
"integrity": "sha1-4IWJqJz80HZZW5MBwdYY9U2nMyk="
|
||||
},
|
||||
"react-native-permissions": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-1.1.1.tgz",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"react-native-confirmation-code-input": "^1.0.4",
|
||||
"react-native-gesture-handler": "^1.0.15",
|
||||
"react-native-ionicons": "^4.5.5",
|
||||
"react-native-loader": "^1.2.1",
|
||||
"react-native-qrcode-scanner": "^1.1.2",
|
||||
"react-native-ui-kitten": "^3.1.2",
|
||||
"react-native-vector-icons": "^6.1.0",
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
- [Henrique Dias]()
|
||||
- [Filipe Pinho]()
|
||||
- [João Borges]()
|
||||
- [Zé Valdeviesso]()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|