screens/dashboard/index.js
// @flow
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { Container } from 'native-base';
import { LinearGradient } from 'expo-linear-gradient';
import {
Alert,
Animated,
Dimensions,
Image,
Platform,
ScrollView,
StatusBar,
StyleSheet,
Text,
TouchableHighlight,
View,
YellowBox
} from 'react-native';
import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome5';
import * as R from 'ramda';
import GoalMessageBox from '../../components/goal-message-box';
import * as actionCreators from './actions';
import commonStyles from '../../styles/common';
import MoneyMeter from '../../components/money-meter';
import MenuCircle from '../../components/menu-circle';
import GoalsBox from '../../components/goals-box';
import pkg from '../../package.json';
const styles = StyleSheet.create(commonStyles);
YellowBox.ignoreWarnings(['Setting a timer']);
type PropsType = {
actions: Object,
profile: Object,
navigation: Object,
completedGoals: Array<Object>,
incompleteGoals: Array<Object>,
submittedGoals: Array<Object>
};
class Dashboard extends Component<PropsType> {
constructor(props) {
super(props);
this.ellipsisToggle = this.ellipsisToggle.bind(this);
this.ellipsisLogoutAlert = this.ellipsisLogoutAlert.bind(this);
this.state = {
expanded1: false,
expanded2: false,
expanded3: false,
menuScale: new Animated.Value(0.01)
};
this.icons = {
dots: 'ellipsis-v',
open: 'angle-down',
close: 'angle-up'
};
}
ellipsisToggle() {
// Toggle circular menu open/close
if (this.state.menuScale._value <= 0.01) {
Animated.timing(
this.state.menuScale,
{
toValue: 1,
duration: 500
}
).start();
} else if (this.state.menuScale._value === 1.0) {
Animated.timing(
this.state.menuScale,
{
toValue: 0,
duration: 500
}
).start();
}
}
ellipsisLogoutAlert() {
const logoutCallback = this.props.actions.logout;
Alert.alert(
'Do you want to logout?',
'This will return you to the login screen.',
[
{ text: 'Logout', onPress: logoutCallback },
{ text: 'Cancel', onPress: this.ellipsisToggle, style: 'cancel' }
],
{ cancelable: false }
);
}
render() {
const { actions, profile, completedGoals, incompleteGoals, submittedGoals, navigation } = this.props;
const incentivesEarned = profile.incentivesEarned || 0;
const incentivesAvailable = 750;
const percentComplete = Math.floor((incentivesEarned / incentivesAvailable) * 100);
const updateGoal = (uid => goal => changes => () => {
actions.updateGoal(uid, goal, changes);
})(profile.uid);
const allButFirst = R.compose(
R.map(goal => (
<GoalMessageBox
goal={goal}
gotoDetails={() => navigation.navigate('GoalDetails', { goal })}
message={[goal.title, goal.detail]}
key={goal.id}
updateGoal={!goal.completed ? updateGoal(goal) : () => (void 0)}
/>
)),
R.slice(1, Infinity)
);
const currentGoalVerbiage = incompleteGoals.length > 0
? [incompleteGoals[0].title, incompleteGoals[0].detail]
: ['Let\'s work together on some goals to move you forward.', 'Schedule an appointment with your counselor today!'];
const firstCompletedGoalVerbiage = completedGoals.length > 0
? [completedGoals[0].title, completedGoals[0].detail]
: ['Keep up the good work.', 'You\'ll finish a goal soon!'];
const firstSubmittedGoalVerbiage = submittedGoals.length > 0
? [submittedGoals[0].title, submittedGoals[0].detail]
: ['You have no goals pending review', 'Keep on working'];
const dots = this.icons.dots;
return (
<Container>
{Platform.OS === 'ios' && <StatusBar barStyle='default' />}
<View style={styles.dashRow}>
<View style={styles.titleRow}>
<Image
source={require('../../assets/images/FinancialFuturesLogo.jpg')}
style={
{
position: 'absolute',
left: -55,
top: 18,
width: '100%',
height: 40,
resizeMode: 'contain'
}
}
/>
<Text style={[styles.title, { marginLeft: 100 }]}>{' '}</Text>
</View>
<View style={styles.dots}>
<Animated.View
style={{
position: 'absolute',
transform: [
{ scale: this.state.menuScale }
],
top: -125,
left: -133
}}
>
<TouchableHighlight
onPress={() => this.ellipsisLogoutAlert()}
underlayColor='transparent'
style={{
width: 300,
height: 300,
zIndex: 1
}}
>
<View>
<MenuCircle />
<Text style={styles.logoutText}>Log out</Text>
</View>
</TouchableHighlight>
</Animated.View>
<TouchableHighlight
onPress={this.ellipsisToggle}
underlayColor='transparent'
>
<Icon
name={dots}
style={styles.ellipsis}
/>
</TouchableHighlight>
</View>
</View>
<LinearGradient
colors={['#fff', '#04a0c6']}
style={
{
position: 'absolute',
left: 0,
right: 0,
top: 60,
height: (Dimensions.get('window').height - 60),
zIndex: -1
}
}
/>
<ScrollView style={styles.main}>
<View style={styles.progressBox}>
<View style={styles.spaceRow}>
<Text style={[styles.bigTitle, styles.bigLetters]}>{`$${incentivesEarned}`}</Text>
<Text style={styles.bigBlock} />
<Text style={styles.bigTitle}>{`${percentComplete}% Complete!`}</Text>
</View>
<View style={styles.dashRow}>
<View style={styles.smallerBlock}>
<Text style={styles.bigBlock} />
<Text style={[styles.money, styles.end]}>{'$0'}</Text>
</View>
<View style={styles.bottomLine}>
<MoneyMeter percentComplete={percentComplete} />
</View>
<View style={styles.smallerBlock}>
<Text style={styles.bigBlock} />
<Text style={[styles.money, styles.start]}>{'$' + incentivesAvailable}</Text>
</View>
<Text style={styles.moreButton} />
</View>
</View>
<GoalsBox
onExpand={isExpanded => {
this.setState({ expanded1: isExpanded });
}}
showExpandButton={(incompleteGoals || []).length > 1}
title={'CURRENT GOALS:'}
>
<GoalMessageBox
goal={incompleteGoals[0]}
message={currentGoalVerbiage}
gotoDetails={() => navigation.navigate('GoalDetails', { goal: incompleteGoals[0] || {} })}
updateGoal={updateGoal(incompleteGoals[0])}
/>
{this.state.expanded1 && allButFirst(incompleteGoals)}
</GoalsBox>
<GoalsBox
onExpand={isExpanded => {
this.setState({ expanded2: isExpanded });
}}
showExpandButton={(submittedGoals || []).length > 1}
title={'SUBMITTED GOALS:'}
>
<GoalMessageBox
goal={submittedGoals[0]}
message={firstSubmittedGoalVerbiage}
gotoDetails={() => navigation.navigate('GoalDetails', { goal: submittedGoals[0] || {} })}
updateGoal={updateGoal(submittedGoals[0])}
/>
{this.state.expanded2 && allButFirst(submittedGoals)}
</GoalsBox>
<GoalsBox
onExpand={isExpanded => {
this.setState({ expanded3: isExpanded });
}}
showExpandButton={(completedGoals || []).length > 1}
title={'COMPLETED GOALS:'}
>
<GoalMessageBox
goal={completedGoals[0]}
gotoDetails={() => navigation.navigate('GoalDetails', { goal: completedGoals[0] || {} })}
message={firstCompletedGoalVerbiage}
updateGoal={() => (void 0)}
/>
{this.state.expanded3 && allButFirst(completedGoals)}
</GoalsBox>
<Text style={{ textAlign: 'center', lineHeight: 30, color: '#427CAB' }}>Version {pkg.version}</Text>
</ScrollView>
</Container>
);
}
}
const mapStateToProps = (state) => {
const profile = state.dashboard.profile || {};
const session = state.login.session;
const [completedGoals, otherGoals] = R.partition(goal => goal.completed, state.dashboard.goals || []);
const [submittedGoals, incompleteGoals] = R.partition(goal => goal.submittedForReview, otherGoals || []);
return { session, profile, completedGoals, submittedGoals, incompleteGoals };
};
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(actionCreators, dispatch)
});
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);