From 15b0a8fa53d60a272d5a69e1f6eb4fab1fc7bbe1 Mon Sep 17 00:00:00 2001 From: Michael Chen Date: Wed, 25 Dec 2019 00:37:20 +0800 Subject: [PATCH] JSAEM2-11 feat: apply filter to transaction view (#16) * JSAEM2-11 feat: apply filter to transaction view * JSAEM2-11 apply requested changes * JSAEM 2-11 fixed: lint issue * JSAEM 2-11 fixed: requested changes from QA --- src/Common/LargeBtn.jsx | 41 +++++++++++++++++++++++++--------------- src/Common/themeStyle.js | 10 +++------- src/Stats/FilterBtn.jsx | 33 +++++++++++++++++++++++++++++--- src/Stats/index.jsx | 32 ++++++++++++++++++++++++++----- src/Stats/utils.js | 18 +++++++++--------- 5 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/Common/LargeBtn.jsx b/src/Common/LargeBtn.jsx index 236098a..da02706 100644 --- a/src/Common/LargeBtn.jsx +++ b/src/Common/LargeBtn.jsx @@ -1,29 +1,38 @@ import React from 'react'; -import { View, Text } from 'react-native'; +import { View, Text, TouchableOpacity } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import PropTypes from 'prop-types'; import styles from './themeStyle'; import themeColor from './Color'; export default function LargeButton({ - subtitle, title, note, bgColor, btnWidth, + subtitle, title, note, bgColor, btnWidth, pressHandler, isShadowVisible, }) { const btnStyle = `${bgColor}LargeBtn`; + return ( - - - {subtitle} - - {title} - - {note} - + + + + {subtitle} + + {title} + + {note} + + + ); } @@ -33,6 +42,8 @@ LargeButton.propTypes = { note: PropTypes.string, bgColor: PropTypes.string, btnWidth: PropTypes.string, + pressHandler: PropTypes.func.isRequired, + isShadowVisible: PropTypes.bool.isRequired, }; LargeButton.defaultProps = { diff --git a/src/Common/themeStyle.js b/src/Common/themeStyle.js index 16830b7..6dbfaac 100644 --- a/src/Common/themeStyle.js +++ b/src/Common/themeStyle.js @@ -83,18 +83,14 @@ const styles = StyleSheet.create({ redLargeBtn: { marginTop: 20, shadowColor: '#f38aa9', - shadowOffset: { - width: 0, - height: 6, - }, - shadowOpacity: 0.70, - shadowRadius: 4.65, - elevation: 8, }, greenLargeBtn: { marginTop: 20, shadowColor: '#70ea93', + }, + + largeBtnShadow: { shadowOffset: { width: 0, height: 6, diff --git a/src/Stats/FilterBtn.jsx b/src/Stats/FilterBtn.jsx index e2bfed6..00a10d9 100644 --- a/src/Stats/FilterBtn.jsx +++ b/src/Stats/FilterBtn.jsx @@ -1,13 +1,40 @@ import React from 'react'; +import PropTypes from 'prop-types'; import LargeButton from '../Common/LargeBtn'; -export default function FilterBtn() { +export default function FilterBtn({ + currentFilter, onFilterChange, totalExpense, totalIncome, +}) { const numberOfBtns = 2; const btnWidth = `${100 / numberOfBtns - 2}%`; + return ( <> - - + onFilterChange('Expense')} + /> + onFilterChange('Income')} + /> ); } + +FilterBtn.propTypes = { + currentFilter: PropTypes.string.isRequired, + onFilterChange: PropTypes.func.isRequired, + totalExpense: PropTypes.number.isRequired, + totalIncome: PropTypes.number.isRequired, +}; diff --git a/src/Stats/index.jsx b/src/Stats/index.jsx index 2af0c0c..31d21ec 100644 --- a/src/Stats/index.jsx +++ b/src/Stats/index.jsx @@ -17,6 +17,7 @@ export default function Stats() { const [view, setCurrentView] = useState('month'); const [timePeriodOptions, setTimePeriod] = useState(utils.getDateSet(moment(), view)); const [isOverlayVisible, setOverlayVisibility] = useState(false); + const [transFilter, setTransFilter] = useState('all'); const updateHeaderView = (type) => { setCurrentView(type); @@ -24,11 +25,27 @@ export default function Stats() { setOverlayVisibility(!isOverlayVisible); }; - const filterListView = (transactionRecords) => { - const current = timePeriodOptions[1]; - return utils.filterData(transactionRecords, current, view); + const filterTransactions = (transactionsList) => { + const transactionsWithSpecificType = utils.filterTransactionByType( + transactionsList, + transFilter, + ); + return utils.filterTransactionsByDate( + transactionsWithSpecificType, + timePeriodOptions[1], + view, + ); }; + const calculateSumByType = (dataList, type) => dataList + .filter((item) => item.type === type) + .reduce((sum, { amount }) => sum + parseFloat(amount), 0); + + const filteredTransactions = filterTransactions(transactions); + const processedTransactions = utils.groupTransactionsByDate(filteredTransactions); + const totalExpense = calculateSumByType(filteredTransactions, 'Expense'); + const totalIncome = calculateSumByType(filteredTransactions, 'Income'); + return ( @@ -51,12 +68,17 @@ export default function Stats() { - + (newFilter === transFilter ? setTransFilter('all') : setTransFilter(newFilter))} + totalExpense={totalExpense} + totalIncome={totalIncome} + /> {(transactions.length !== 0) ? ( ) : } diff --git a/src/Stats/utils.js b/src/Stats/utils.js index e38a594..ed43b51 100644 --- a/src/Stats/utils.js +++ b/src/Stats/utils.js @@ -41,23 +41,22 @@ const getDateSet = (current, type) => [ current.clone().add(1, type), ]; -const filterData = (dataList, range, view) => { +const filterTransactionsByDate = (dataList, range, view) => { const monthRange = range.format('MMM YYYY'); const yearRange = range.format('YYYY'); - let result; + switch (view) { case 'month': - result = dataList.filter((value) => moment(value[0].date, 'MMMM Do YYYY').format('MMM YYYY') === monthRange); - break; + return dataList.filter((value) => moment.unix(value.date).format('MMM YYYY') === monthRange); case 'year': - result = dataList.filter((value) => moment(value[0].date, 'MMMM Do YYYY').format('YYYY') === yearRange); - break; + return dataList.filter((value) => moment.unix(value.date).format('YYYY') === yearRange); default: - break; + return []; } - return result; }; +const filterTransactionByType = (dataList, type) => (type === 'all' ? dataList : dataList.filter((item) => (item.type === type))); + const transType = (amount, type) => (type === 'Expense' ? `-$${amount}` : `+$${amount}`); export default { @@ -65,6 +64,7 @@ export default { sumAmount, groupTransactionsByDate, getDateSet, - filterData, + filterTransactionsByDate, + filterTransactionByType, transType, };