Skip to content

Commit

Permalink
Points History and Rewards tab bar styling + Rewards navigation anima…
Browse files Browse the repository at this point in the history
…tions (#46)

* Created and implemented new CircleIcon component

* Transaction card and points history styling

* Added total sale to transaction cards

* Fixed points earned Airtable language

* Fixed text colors to match designs

* Rewards tab bar styling

* Fixed 'Available' typo, cleaning up

* Cleaning up Top Tab heading styling

* Made RootStack to open Rewards as a modal

* Corrected capitalization of overlines

* Fixed direct link to 'Points History' from drawer

* Fixed reload bug on closing rewards
  • Loading branch information
wangannie authored Mar 26, 2020
1 parent eefed52 commit 9f3b344
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 270 deletions.
11 changes: 11 additions & 0 deletions components/BaseComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ export const NavButton = styled.TouchableOpacity`
justify-content: center;
`;

export const CircleIconContainer = styled.View`
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
padding: 8px;
border-radius: 20px;
background-color: ${props => props.color || Colors.lighterGreen};
`;

export const ButtonContainer = styled.TouchableOpacity``;
// TODO @tommypoa Replace top / bottom 25%
export const ButtonLabel = styled(TextButton)`
Expand Down
19 changes: 19 additions & 0 deletions components/CircleIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FontAwesome5 } from '@expo/vector-icons';
import React from 'react';
import { CircleIconContainer } from './BaseComponents';

export default class CircleIcon extends React.Component {
render() {
return (
<CircleIconContainer color={this.props.circleColor}>
<FontAwesome5
name={this.props.icon}
size={22}
solid
color={this.props.iconColor}
style={{ paddingTop: 1 }}
/>
</CircleIconContainer>
);
}
}
19 changes: 8 additions & 11 deletions components/resources/ResourceCategoryBar.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import React from 'react';

import {
CategoryCard,
CategoryIcon,
HeadingContainer
} from '../../styled/resources';
import Colors from '../../assets/Colors';
import { CategoryCard, HeadingContainer } from '../../styled/resources';
import { Title } from '../BaseComponents';
import { FontAwesome5 } from '@expo/vector-icons';
import CircleIcon from '../CircleIcon';

class ResourceCategoryBar extends React.Component {
render() {
return (
<CategoryCard>
<CategoryIcon>
<FontAwesome5 name={this.props.icon} size={20} solid color={'#fff'} />
</CategoryIcon>

<CircleIcon
icon={this.props.icon}
iconColor={Colors.lightest}
circleColor={Colors.lighterGreen}
/>
<HeadingContainer>
<Title>{this.props.title}</Title>
</HeadingContainer>
Expand Down
39 changes: 16 additions & 23 deletions components/rewards/PointsHistory.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
import React from 'react';
import { Button, ScrollView, StyleSheet, Text, View } from 'react-native';
import { ScrollView, View } from 'react-native';
import { Overline } from '../BaseComponents';
import Transaction from './Transaction';
/**
* @prop
* */

const styles = StyleSheet.create({
signOutButton: {
fontSize: 20,
paddingVertical: 15
}
});

function PointsHistory({ transactions, user, updates, navigation }) {
// Only display if transactions have mounted
// TODO @kennethlien fix spacing at line 44
if (transactions) {
return (
<View>
<View>
<ScrollView>
<Overline style={{ marginTop: 24 }}>Recent Transactions</Overline>
{transactions.map(transaction => (
<Transaction
key={transaction.id}
date={transaction.date}
points={transaction.points}
storeName={transaction.storeName}
/>
))}
</ScrollView>
</View>
</View>
<ScrollView style={{ marginLeft: 16, paddingRight: 16 }}>
<Overline style={{ marginTop: 24, marginBottom: 12 }}>
Recent Transactions
</Overline>
{transactions.map(transaction => (
<Transaction
key={transaction.id}
date={transaction.date}
pointsEarned={transaction.pointsEarned}
storeName={transaction.storeName}
subtotal={transaction.subtotal}
totalSale={transaction.totalSale}
/>
))}
</ScrollView>
);
}
// else return
Expand Down
22 changes: 9 additions & 13 deletions components/rewards/RewardsCard.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import React from 'react';
import Colors from '../../assets/Colors';
import {
RewardsCardContainer,
RewardDescriptionContainer,
StarIcon
RewardsCardContainer
} from '../../styled/rewards';
import { Subhead, Caption } from '../BaseComponents';
import { FontAwesome5 } from '@expo/vector-icons';
import Colors from '../../assets/Colors';
import { Caption, Subhead } from '../BaseComponents';
import CircleIcon from '../CircleIcon';

class RewardsCard extends React.Component {
render() {
return (
<RewardsCardContainer>
<StarIcon>
<FontAwesome5
name="star"
solid
size={24}
color={Colors.primaryGreen}
/>
</StarIcon>
<CircleIcon
icon="star"
iconColor={Colors.primaryGreen}
circleColor={Colors.lightest}
/>
<RewardDescriptionContainer>
<Subhead color={Colors.darkerGreen}>$5 Reward</Subhead>
<Caption color={Colors.darkerGreen}>1000 points</Caption>
Expand Down
73 changes: 38 additions & 35 deletions components/rewards/RewardsHome.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { View, ScrollView } from 'react-native';
import { Body, Overline, Title } from '../BaseComponents';
import { ScrollView } from 'react-native';
import { ProgressBar } from 'react-native-paper';
import Colors from '../../assets/Colors';
import {
RewardsProgressContainer,
AvailiableRewardsContainer
AvailableRewardsContainer,
RewardsProgressContainer
} from '../../styled/rewards';
import { ProgressBar } from 'react-native-paper';
import { Body, Overline, Title } from '../BaseComponents';
import RewardsCard from './RewardsCard';
import Colors from '../../assets/Colors';

/**
* @prop
Expand All @@ -23,35 +23,38 @@ function createList(N) {

function RewardsHome({ user }) {
return (
<View>
<ScrollView>
<RewardsProgressContainer>
<Overline style={{ marginTop: 24, marginBottom: 15 }}>
REWARD PROGRESS
</Overline>
<Title style={{ marginBottom: 2 }}>
{parseInt(user.points) % 1000} / 1000
</Title>
<ProgressBar
style={{ height: 20, borderRadius: 20, marginBottom: 15 }}
progress={(parseInt(user.points) % 1000) / 1000}
color={Colors.primaryGreen}
/>
<Body style={{ marginBottom: 28 }}>
Earn {`${1000 - (parseInt(user.points) % 1000)}`} points to unlock
your next $5 reward
</Body>
<Overline style={{ marginBottom: 8 }}>
AVAILIABLE REWARDS ({Math.floor(parseInt(user.points) / 1000)})
</Overline>
</RewardsProgressContainer>
<AvailiableRewardsContainer>
{createList(Math.floor(parseInt(user.points) / 1000)).map(a => (
<RewardsCard></RewardsCard>
))}
</AvailiableRewardsContainer>
</ScrollView>
</View>
<ScrollView style={{ marginLeft: 16, paddingRight: 16 }}>
<RewardsProgressContainer>
<Overline style={{ marginTop: 24, marginBottom: 12 }}>
Reward Progress
</Overline>
<Title style={{ marginBottom: 2 }}>
{parseInt(user.points) % 1000} / 1000
</Title>
<ProgressBar
style={{
height: 20,
width: '100%',
borderRadius: 20,
marginBottom: 15
}}
progress={(parseInt(user.points) % 1000) / 1000}
color={Colors.primaryGreen}
/>
<Body style={{ marginBottom: 28 }}>
Earn {`${1000 - (parseInt(user.points) % 1000)}`} points to unlock
your next $5 reward
</Body>
<Overline style={{ marginBottom: 8 }}>
Available Rewards ({Math.floor(parseInt(user.points) / 1000)})
</Overline>
</RewardsProgressContainer>
<AvailableRewardsContainer>
{createList(Math.floor(parseInt(user.points) / 1000)).map(a => (
<RewardsCard></RewardsCard>
))}
</AvailableRewardsContainer>
</ScrollView>
);
}

Expand Down
51 changes: 29 additions & 22 deletions components/rewards/Transaction.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
import { FontAwesome5 } from '@expo/vector-icons';
import React from 'react';
import { TouchableOpacity } from 'react-native';
import {
Card,
ContentContainer,
IconContainer
} from '../../styled/transaction';
import { Caption, Body } from '../../components/BaseComponents';
import Colors from '../../assets/Colors';
import { displayDollarValue } from '../../lib/rewardsUtils';
import { Card, ContentContainer } from '../../styled/transaction';
import { Caption, Subhead } from '../BaseComponents';
import CircleIcon from '../CircleIcon';

/**
* @prop
* */

function Transaction(props) {
const { date, storeName, points } = props;
const { date, storeName, pointsEarned, totalSale } = props;
const options = {
weekday: 'short',
year: 'numeric',
month: 'short',
day: 'numeric'
};
return (
<TouchableOpacity>
<Card>
<IconContainer>
<FontAwesome5 name="check" size={32} color="green" />
</IconContainer>
<ContentContainer>
<Body>
{date.toLocaleDateString()} @ {storeName}
</Body>
<Caption>{points} Points Redeemed</Caption>
</ContentContainer>
</Card>
</TouchableOpacity>
<Card>
<CircleIcon
icon="check"
iconColor={Colors.primaryGreen}
circleColor={Colors.lightestGreen}
/>
<ContentContainer>
<Caption color={Colors.secondaryText}>
{date.toLocaleDateString('en-US', options)}{storeName}
</Caption>
<Subhead>{pointsEarned} points earned</Subhead>
<Caption color={Colors.secondaryText}>
for {displayDollarValue(totalSale ? totalSale : 0)} of healthy
products
</Caption>
</ContentContainer>
</Card>
);
}

Expand Down
11 changes: 9 additions & 2 deletions lib/rewardsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ function createTransactionData(record) {
customer: transaction.Customer,
// TODO not entirely sure why this was converted to a Date object
date: new Date(transaction.Date),
points: transaction['Points Rewarded'],
pointsEarned: transaction['Points Earned'],
storeName: transaction['Store Name'],
productsPurchased: transaction['Products Purchased'],
phone: transaction['Customer Lookup (Phone #)'],
clerk: transaction.Clerk,
itemsRedeemed: transaction['Items Redeemed'],
customerName: transaction['Customer Name'],
receipts: transaction.Receipts
totalSale: transaction['Total Price']
};
}
export function displayDollarValue(amount, positive = true) {
const dollarValue = '$'.concat(amount.toFixed(2).toString());
if (positive) {
return dollarValue;
}
return '-'.concat(dollarValue);
}

// Calls Airtable API to return a promise that
// will resolve to be a user record.
Expand Down
22 changes: 15 additions & 7 deletions navigation/AppNavigator.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React from 'react';
import { AsyncStorage, View, TouchableOpacity, Linking } from 'react-native';
import { AsyncStorage, Linking, TouchableOpacity, View } from 'react-native';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createDrawerNavigator, DrawerItems } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack';
import WelcomeScreen from '../screens/auth/WelcomeScreen';
import Colors from '../assets/Colors';
import { Title } from '../components/BaseComponents';
import { getUser } from '../lib/rewardsUtils';
import LoginScreen from '../screens/auth/LoginScreen';
import SignUpScreen from '../screens/auth/SignUpScreen';
import Colors from '../assets/Colors';
import { getUser } from '../lib/rewardsUtils';
import { RewardsStack, StoresStack, ResourcesStack } from './StackNavigators';
import WelcomeScreen from '../screens/auth/WelcomeScreen';
import RewardsScreen from '../screens/rewards/RewardsScreen';
import { ResourcesStack, RootStack, StoresStack } from './StackNavigators';

const AuthStack = createStackNavigator({
Welcome: WelcomeScreen,
Expand Down Expand Up @@ -119,16 +120,23 @@ export class DrawerContent extends React.Component {

const MyDrawerNavigator = createDrawerNavigator(
{
Root: {
screen: RootStack,
navigationOptions: () => ({
title: 'Root',
drawerLabel: () => null
})
},
Stores: {
screen: StoresStack,
navigationOptions: () => ({
title: 'Stores'
})
},
Rewards: {
screen: RewardsStack,
screen: props => <RewardsScreen {...props} tab={1} />,
navigationOptions: () => ({
title: 'Your Profile',
title: 'Points History',
drawerLockMode: 'locked-closed'
})
},
Expand Down
Loading

0 comments on commit 9f3b344

Please sign in to comment.