Skip to content

Commit

Permalink
Improve trends
Browse files Browse the repository at this point in the history
  • Loading branch information
DaxiALex authored and DaxiALex committed Jun 6, 2018
1 parent 6d64a6e commit e54f1c2
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 440 deletions.
69 changes: 41 additions & 28 deletions app/modules/transactions/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const getAccountId = (_, props) => R.pathOr('0', ['accountId'], props);

export const getTransactions = createSelector(
[getTransactionsIds, getTransactionsEntities, getDateForFiltering],
(ids, entities, date) => {
(transIds, transEnt, date) => {
const newArray = [];
ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ?
date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date)) {
Expand All @@ -32,10 +32,10 @@ export const getTransactions = createSelector(

export const getFavouritesTransactions = createSelector(
[getTransactionsIds, getTransactionsEntities, getDateForFiltering],
(ids, entities, date) => {
(transIds, transEnt, date) => {
const newArray = [];
ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ?
date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date) && transaction.isFavourite) {
Expand All @@ -56,11 +56,11 @@ export const getAccountsStats = createSelector(
getCategoryTypeForFiltering,
getAccountsEntities,
],
(ids, entities, date, categorEnt, categorType, accountsEnt) => {
(transIds, transEnt, date, categorEnt, categorType, accountsEnt) => {
const data = {};
const type = categorType === 0 ? types.income : types.expense;
ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ? date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date) && categorEnt[transaction.category].type === type) {
data[transaction.account] = {
Expand All @@ -81,15 +81,15 @@ export const getAccountsStats = createSelector(
},
);

// TODO Refactor this function
// TODO Refactor selectors
export const getTrendsStats = createSelector(
[
getTransactionsIds,
getTransactionsEntities,
getDateForFiltering,
getCategoriesEntities,
],
(ids, entities, date, categorEnt) => {
(transIds, transEnt, date, categorEnt) => {
const data = {
Income: {},
Expense: {},
Expand All @@ -99,21 +99,23 @@ export const getTrendsStats = createSelector(
totalExpense: 0,
};

const diff = moment(date.to).diff(date.from, 'month');
const def = {};
// If the difference between months is more than 12,
// then miss months in which both, total expense and total income equal 0.
const monthsDiff = moment(date.to).diff(date.from, 'month');
const initialValue = {};

if (diff <= 12) {
for (let i = 0; i <= diff; i++) { // eslint-disable-line
if (monthsDiff <= 12) {
for (let i = 0; i <= monthsDiff; i++) { // eslint-disable-line
const key = moment(date.to).subtract(i, 'months').startOf('month');
def[key] = 0;
initialValue[key] = 0;
data.tickValues.push(key.toString());
}
data.Income = def;
data.Expense = def;
data.Income = initialValue;
data.Expense = initialValue;
}

ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ? date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date)) {
const type = categorEnt[transaction.category].type;
Expand All @@ -134,6 +136,14 @@ export const getTrendsStats = createSelector(
...data[type],
[startOfMonth]: currentValue,
};

const otherType = type === types.income ? types.expense : types.income;
if (!R.pathOr(false, [otherType, startOfMonth], data)) {
data[otherType] = {
...data[otherType],
[startOfMonth]: 0,
};
}
}
});

Expand All @@ -152,12 +162,15 @@ export const getTrendsStats = createSelector(
Income.forEach((element, id) => element.x = id + 1); // eslint-disable-line
Expense.forEach((element, id) => element.x = id + 1); // eslint-disable-line

const maxValue = data.maxValue + data.maxValue / 12;

return {
Income,
Expense,
tickValues: data.tickValues,
maxValue: data.maxValue + 200,
maxValue,
totalIncome: data.totalIncome,
totalExpense: -data.totalExpense,
};
},
);
Expand All @@ -170,12 +183,12 @@ export const getCategoriesStats = createSelector(
getCategoriesEntities,
getCategoryTypeForFiltering,
],
(ids, entities, date, categorEnt, categorType) => {
(transIds, transEnt, date, categorEnt, categorType) => {
const data = {};
let total = 0;
const type = categorType === 0 ? types.income : types.expense;
ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ? date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date) && categorEnt[transaction.category].type === type) {
data[transaction.category] = {
Expand All @@ -192,7 +205,7 @@ export const getCategoriesStats = createSelector(
id: key,
name: val.name,
value: val.value,
percent: Math.round(val.value * 100 / total),
percent: Math.round(val.value * 1000 / total) / 10,
});
}, data
);
Expand All @@ -207,10 +220,10 @@ export const getCurrentAccountTransaction = createSelector(
getDateForFiltering,
getAccountId,
],
(ids, entities, date, accId) => {
(transIds, transEnt, date, accId) => {
const newArray = [];
ids.forEach((id) => {
const transaction = entities[id];
transIds.forEach((id) => {
const transaction = transEnt[id];
const period = !date.format ?
date : { from: +date.startOf('day'), to: +date.endOf('day') };
if (inPeriod(period, transaction.date) && transaction.account === accId) {
Expand Down
70 changes: 39 additions & 31 deletions app/screens/Trends/TrendsScreenView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
// import T from 'prop-types';
import T from 'prop-types';
import { View, ScrollView, Text } from 'react-native';
import {
VictoryGroup,
Expand All @@ -19,8 +19,10 @@ import { colors, fontSizes } from '../../styles';
import { formatMonthWithYear } from '../../utils/dateHelpers';

const chartHeight = 375;
const getChartWidth = length => (length * 60 + 60 < 400 ? 330 : length * 60 + 60);
const getBarLabelPadding = (currentValue, maxValue) =>
(maxValue / currentValue < 3.5 ? ((chartHeight - 40) * currentValue / maxValue / 2) : -5);

const getChartWidth = width => width * 60 + 60 < 400 ? 330 : width * 60 + 60;

const Trends = ({
dateForFiltering,
Expand All @@ -40,31 +42,38 @@ const Trends = ({
/>
<Separator />

<View style={s.mainContainer}>
<View style={s.container}>
<View style={s.chartContainer}>

<ScrollView horizontal style={{ paddingLeft: 50 }} bounces={false}>
<ScrollView
horizontal
bounces={false}
showsHorizontalScrollIndicator={stats.tickValues.length > 1}
>
<VictoryChart
height={chartHeight}
padding={{ top: 25, bottom: 50, right: 40 }}
padding={{ top: 25, bottom: 50, left: 50 }}
width={getChartWidth(stats.tickValues.length)}
domainPadding={{ x: [50, 60] }}
domainPadding={{ x: [50, 50] }}
>
<VictoryAxis
height={chartHeight}
dependentAxis
domain={[1, stats.maxValue]}
width={48}
width={50}
style={{
grid: { stroke: colors.grey, strokeWidth: 0.5 },
axis: { stroke: colors.white },
tickLabels: { fill: colors.white },
}}
/>
<VictoryAxis
height={chartHeight}
tickValues={stats.tickValues}
tickFormat={(d) => formatMonthWithYear(d)}
tickFormat={d => formatMonthWithYear(d)}
style={{
grid: { stroke: colors.grey, strokeWidth: 0.5 },
axis: { stroke: colors.greyVeryDarker },
tickLabels: {
fontSize: fontSizes.verySmall,
stroke: colors.grey,
Expand All @@ -76,43 +85,39 @@ const Trends = ({
<VictoryGroup height={chartHeight} offset={22}>
<VictoryBar
data={stats.Expense}
labels={(d) => d.y !== 0 ? `-${d.y}` : ''}
labels={d => (d.y !== 0 ? `-${d.y}` : '')}
style={{
labels: {
fill: (d) => stats.maxValue / d.y < 3.5 ? colors.white : colors.red,
fontSize: 12 },
data: {
fill: colors.red,
width: 18,
fill: d => (stats.maxValue / d.y < 3.5 ? colors.white : colors.red),
fontSize: 12,
},
data: { fill: colors.red, width: 18 },
}}
labelComponent={
<VictoryLabel
dy={6}
angle={90}
dx={d => stats.maxValue / d.y < 3.5 ? (chartHeight * d.y / 4100 / 2) : -5}
dx={d => getBarLabelPadding(d.y, stats.maxValue)}
/>
}
animate={{ duration: 500, onLoad: { duration: 200 } }}
/>
<VictoryBar
data={stats.Income}
labels={(d) => d.y !== 0 ? `+${d.y}` : ''}
labels={d => (d.y !== 0 ? `+${d.y}` : '')}
style={{
labels: {
fill: (d) => stats.maxValue / d.y < 3.5 ? colors.white : colors.green,
fontSize: 12 },
data: {
fill: colors.green,
width: 18,
fill: d => (stats.maxValue / d.y < 3.5 ? colors.white : colors.green),
fontSize: 12,
},
data: { fill: colors.green, width: 18 },
}}
labelComponent={<VictoryLabel
dy={6}
angle={90}
dx={d => stats.maxValue / d.y < 3.5 ? (chartHeight * d.y / 4100 / 2) : -5}
/>}
animate={{ duration: 500, onLoad: { duration: 200 } }}
labelComponent={
<VictoryLabel
dy={6}
angle={90}
dx={d => getBarLabelPadding(d.y, stats.maxValue)}
/>
}
/>
</VictoryGroup>
</VictoryChart>
Expand All @@ -122,14 +127,16 @@ const Trends = ({
<View style={s.verticalAxisContainer}>
<VictoryAxis
height={chartHeight}
padding={{ top: 24, left: 50, bottom: 50 }}
padding={{ top: 24, left: 50, bottom: 51.3 }}
dependentAxis
domain={[1, stats.maxValue]}
width={50}
style={{
grid: { stroke: colors.grey, strokeWidth: 0.5 },
axis: { stroke: colors.greyVeryDarker, strokeWidth: 2 },
tickLabels: {
fontSize: fontSizes.verySmall,
padding: 6,
stroke: colors.grey,
fill: colors.greyVeryDarker,
strokeWidth: 0.5,
Expand Down Expand Up @@ -158,13 +165,14 @@ const Trends = ({

</View>

<Separator />
</View>
</View>
);

Trends.propTypes = {

dateForFiltering: T.object,
setDateForFiltering: T.func,
stats: T.object,
};

export default Trends;
Loading

0 comments on commit e54f1c2

Please sign in to comment.