diff --git a/components/BaseComponents.js b/components/BaseComponents.js index 1211e38b..72f5be0b 100644 --- a/components/BaseComponents.js +++ b/components/BaseComponents.js @@ -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)` diff --git a/components/CircleIcon.js b/components/CircleIcon.js new file mode 100644 index 00000000..736a38eb --- /dev/null +++ b/components/CircleIcon.js @@ -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 ( + + + + ); + } +} diff --git a/components/resources/ResourceCategoryBar.js b/components/resources/ResourceCategoryBar.js index 350a46ed..f93154d8 100644 --- a/components/resources/ResourceCategoryBar.js +++ b/components/resources/ResourceCategoryBar.js @@ -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 ( - - - - + {this.props.title} diff --git a/components/rewards/PointsHistory.js b/components/rewards/PointsHistory.js index 3cd9d0a4..88bea445 100644 --- a/components/rewards/PointsHistory.js +++ b/components/rewards/PointsHistory.js @@ -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 ( - - - - Recent Transactions - {transactions.map(transaction => ( - - ))} - - - + + + Recent Transactions + + {transactions.map(transaction => ( + + ))} + ); } // else return diff --git a/components/rewards/RewardsCard.js b/components/rewards/RewardsCard.js index 85dfc9b0..fb08869b 100644 --- a/components/rewards/RewardsCard.js +++ b/components/rewards/RewardsCard.js @@ -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 ( - - - + $5 Reward 1000 points diff --git a/components/rewards/RewardsHome.js b/components/rewards/RewardsHome.js index 4146186d..249585bb 100644 --- a/components/rewards/RewardsHome.js +++ b/components/rewards/RewardsHome.js @@ -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 @@ -23,35 +23,38 @@ function createList(N) { function RewardsHome({ user }) { return ( - - - - - REWARD PROGRESS - - - {parseInt(user.points) % 1000} / 1000 - - - - Earn {`${1000 - (parseInt(user.points) % 1000)}`} points to unlock - your next $5 reward - - - AVAILIABLE REWARDS ({Math.floor(parseInt(user.points) / 1000)}) - - - - {createList(Math.floor(parseInt(user.points) / 1000)).map(a => ( - - ))} - - - + + + + Reward Progress + + + {parseInt(user.points) % 1000} / 1000 + + + + Earn {`${1000 - (parseInt(user.points) % 1000)}`} points to unlock + your next $5 reward + + + Available Rewards ({Math.floor(parseInt(user.points) / 1000)}) + + + + {createList(Math.floor(parseInt(user.points) / 1000)).map(a => ( + + ))} + + ); } diff --git a/components/rewards/Transaction.js b/components/rewards/Transaction.js index 0e7925e9..42164a86 100644 --- a/components/rewards/Transaction.js +++ b/components/rewards/Transaction.js @@ -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 ( - - - - - - - - {date.toLocaleDateString()} @ {storeName} - - {points} Points Redeemed - - - + + + + + {date.toLocaleDateString('en-US', options)} • {storeName} + + {pointsEarned} points earned + + for {displayDollarValue(totalSale ? totalSale : 0)} of healthy + products + + + ); } diff --git a/lib/rewardsUtils.js b/lib/rewardsUtils.js index 282de18f..6e6e8d25 100644 --- a/lib/rewardsUtils.js +++ b/lib/rewardsUtils.js @@ -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. diff --git a/navigation/AppNavigator.js b/navigation/AppNavigator.js index 8b01df7a..af6f2f92 100644 --- a/navigation/AppNavigator.js +++ b/navigation/AppNavigator.js @@ -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, @@ -119,6 +120,13 @@ export class DrawerContent extends React.Component { const MyDrawerNavigator = createDrawerNavigator( { + Root: { + screen: RootStack, + navigationOptions: () => ({ + title: 'Root', + drawerLabel: () => null + }) + }, Stores: { screen: StoresStack, navigationOptions: () => ({ @@ -126,9 +134,9 @@ const MyDrawerNavigator = createDrawerNavigator( }) }, Rewards: { - screen: RewardsStack, + screen: props => , navigationOptions: () => ({ - title: 'Your Profile', + title: 'Points History', drawerLockMode: 'locked-closed' }) }, diff --git a/navigation/StackNavigators.js b/navigation/StackNavigators.js index 48ca453f..63e34278 100644 --- a/navigation/StackNavigators.js +++ b/navigation/StackNavigators.js @@ -1,16 +1,13 @@ -import { createStackNavigator } from 'react-navigation-stack'; import { Platform } from 'react-native'; - +import { createStackNavigator } from 'react-navigation-stack'; import MapScreen from '../screens/map/MapScreen'; -import RewardsScreen from '../screens/rewards/RewardsScreen'; -import ReceiptScanner from '../screens/rewards/Camera'; - import ProductDetailsScreen from '../screens/map/ProductDetailsScreen'; import ProductsScreen from '../screens/map/ProductsScreen'; import StoreListScreen from '../screens/map/StoreListScreen'; -import NewsScreen from '../screens/news/NewsScreen'; import NewsDetailsScreen from '../screens/news/NewsDetailsScreen'; +import NewsScreen from '../screens/news/NewsScreen'; import ResourcesScreen from '../screens/resources/ResourcesScreen'; +import RewardsScreen from '../screens/rewards/RewardsScreen'; const config = Platform.select({ web: { headerMode: 'screen' }, @@ -31,18 +28,21 @@ StoresStack.navigationOptions = { drawerLabel: 'Stores' }; -export const RewardsStack = createStackNavigator( +export const RootStack = createStackNavigator( { - RewardsHome: RewardsScreen, - Camera: ReceiptScanner + MainStack: { + screen: StoresStack + }, + RewardsOverlay: { + screen: RewardsScreen + } }, - config + { + headerMode: 'none', + mode: 'modal' + } ); -RewardsStack.navigationOptions = { - drawerLabel: 'Points History' -}; - export const NewsStack = createStackNavigator( { News: NewsScreen, diff --git a/screens/map/MapScreen.js b/screens/map/MapScreen.js index f2d9373c..55851ad1 100644 --- a/screens/map/MapScreen.js +++ b/screens/map/MapScreen.js @@ -1,9 +1,9 @@ +import { FontAwesome5 } from '@expo/vector-icons'; import * as Location from 'expo-location'; import * as Permissions from 'expo-permissions'; import convertDistance from 'geolib/es/convertDistance'; import getDistance from 'geolib/es/getDistance'; import React from 'react'; -import { FontAwesome5 } from '@expo/vector-icons'; import { Dimensions, SafeAreaView, @@ -13,17 +13,17 @@ import { } from 'react-native'; import MapView, { Marker } from 'react-native-maps'; import BottomSheet from 'reanimated-bottom-sheet'; +import Colors from '../../assets/Colors'; +import { Subhead } from '../../components/BaseComponents'; import Hamburger from '../../components/Hamburger'; import StoreProducts from '../../components/product/StoreProducts'; import { getProductData, getStoreData } from '../../lib/mapUtils'; -import { Subhead } from '../../components/BaseComponents'; import { - SearchBar, BottomSheetContainer, BottomSheetHeaderContainer, - DragBar + DragBar, + SearchBar } from '../../styled/store'; -import Colors from '../../assets/Colors'; const { width } = Dimensions.get('window'); // full width @@ -256,7 +256,7 @@ export default class MapScreen extends React.Component { alignItems: 'center', justifyContent: 'center' }} - onPress={() => this.props.navigation.navigate('Rewards')}> + onPress={() => this.props.navigation.navigate('RewardsOverlay')}> Your Rewards diff --git a/screens/rewards/RewardsScreen.js b/screens/rewards/RewardsScreen.js index 1d3577d7..8e3a9e64 100644 --- a/screens/rewards/RewardsScreen.js +++ b/screens/rewards/RewardsScreen.js @@ -2,7 +2,8 @@ import { FontAwesome5 } from '@expo/vector-icons'; import React from 'react'; import { AsyncStorage, Dimensions } from 'react-native'; import { TabBar, TabView } from 'react-native-tab-view'; -import { Title } from '../../components/BaseComponents'; +import Colors from '../../assets/Colors'; +import { BigTitle } from '../../components/BaseComponents'; import PointsHistory from '../../components/rewards/PointsHistory'; import RewardsHome from '../../components/rewards/RewardsHome'; import { getCustomerTransactions, getUser } from '../../lib/rewardsUtils'; @@ -16,6 +17,7 @@ const routes = [ export default class RewardsScreen extends React.Component { constructor(props) { super(props); + const tab = this.props.tab || 0; this.state = { user: { id: null, @@ -25,7 +27,7 @@ export default class RewardsScreen extends React.Component { transactions: [], refreshing: false, updates: false, - index: 0, + index: tab, routes }; } @@ -131,6 +133,7 @@ export default class RewardsScreen extends React.Component { @@ -141,18 +144,17 @@ export default class RewardsScreen extends React.Component { return ( - this.props.navigation.navigate('Stores')}> + this.props.navigation.goBack()}> - Healthy Rewards - + ({ - contentContainerStyle: { - paddingTop: 30 - } -}))` - flex: 1; - background-color: #fff; -`; - export const RewardsCardContainer = styled.View` box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2); border-radius: 9px; @@ -34,28 +25,18 @@ export const RewardsCardContainer = styled.View` background-color: ${Colors.lightestGreen}; `; -export const StarIcon = styled.View` - align-items: center; - justify-content: center; - height: 40px; - width: 40px; - border-radius: 20px; - background-color: #fff; - flex-direction: row; -`; - export const RewardDescriptionContainer = styled.View` flex-direction: column; margin-left: 8px; `; export const RewardsProgressContainer = styled.View` - margin: 1% 5%; + margin: 8px 0; flex-direction: column; `; -export const AvailiableRewardsContainer = styled.View` - margin: 1% 5%; +export const AvailableRewardsContainer = styled.View` + margin: 8px 0; display: flex width: 100% flex-direction: row; @@ -63,80 +44,39 @@ export const AvailiableRewardsContainer = styled.View` justify-content: flex-start; `; -export const ContentText = styled(Subhead)``; - -export const ContentText2 = styled(Caption)``; - -export const RewardsTitle = styled.View` - font-size: 17px; - font-weight: bold; - color: rgba(13, 99, 139, 0.8); - line-height: 24px; - text-align: center; -`; export const TopTab = styled.View` - position: absolute; - height: 190px; - top: 0px; background-color: ${Colors.primaryGreen}; - flex-direction: row; - width: 100%; - font-size: 30px; - align-items: flex-end; -`; -// TODO @anniero98 figure out how to pass styles to third-party components (TabView, TabBar) -export const StyledTabView = styled.View` - flex: 1; - margin-top: 150px; + padding-top: 80px; + flex-direction: column; `; +// box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2); export const styles = StyleSheet.create({ tabView: { - flex: 1, - marginTop: 150 + flex: 1 }, tabBar: { - backgroundColor: '#008550', - elevation: 0, + backgroundColor: Colors.primaryGreen, + elevation: 2, borderBottomWidth: 0, - height: 50 + height: 50, + shadowColor: '#000', + shadowOffset: { width: 0, height: 3 }, + shadowOpacity: 0.2, + shadowRadius: 3, + justifyContent: 'flex-end' }, tabBarLabel: { - color: 'white', + color: Colors.lightest, textTransform: 'capitalize', fontSize: 16, - fontWeight: 'bold' + fontFamily: 'poppins-medium', + paddingLeft: 4, + paddingRight: 4 }, tabBarIndicator: { - backgroundColor: '#fff', - height: 2.5 - }, - tabBarInfoContainer: { - position: 'absolute', - bottom: 150, - left: 0, - right: 0, - ...Platform.select({ - ios: { - shadowColor: 'black', - shadowOffset: { width: 0, height: 3 }, - shadowOpacity: 0.1, - shadowRadius: 3 - }, - android: { - elevation: 20 - } - }), - alignItems: 'center', - backgroundColor: '#fbfbfb', - paddingVertical: 20 - }, - navigationFilename: { - marginTop: 5 - }, - getStartedContainer: { - alignItems: 'center', - marginHorizontal: 50, - paddingVertical: 20 + backgroundColor: Colors.lightest, + height: 2, + borderRadius: 10 } }); diff --git a/styled/transaction.js b/styled/transaction.js index f71b270e..babeb80d 100644 --- a/styled/transaction.js +++ b/styled/transaction.js @@ -1,41 +1,23 @@ import styled from 'styled-components/native'; -import { PoppinsText } from './shared'; +import Colors from '../assets/Colors'; export const Card = styled.View` - box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2); - border-style: solid; - border-radius: 4px; border-width: 1px; - border-color: grey; - padding: 20px; - margin: 2% 5%; + border-radius: 4px; + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.12); + box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.14); + border-color: ${Colors.lighter}; + background-color: ${Colors.lightest}; + margin: 8px 0; + padding: 16px 8px; flex-direction: row; -`; - -export const IconContainer = styled.View` - flex: 1; - flex-direction: column; + justify-content: space-between; `; export const ContentContainer = styled.View` - flex: 4; flex-direction: column; -`; - -export const MainText = styled(PoppinsText)` - font-style: normal; - font-weight: normal; - font-size: 16px; - line-height: 24px; - display: flex; - align-items: center; - color: rgba(0, 0, 0, 0.8); -`; - -export const Overline = styled(PoppinsText)` - font-style: normal; - font-weight: 500; - font-size: 12px; - line-height: 16px; - color: #999999; + margin-left: 12px; + flex: 1; + justify-content: flex-start; `;