Skip to content
Snippets Groups Projects
Unverified Commit 2b96bb3d authored by Crazypkr1099's avatar Crazypkr1099 Committed by GitHub
Browse files

Added Year comparison feature. (#2806)


* Added Year comparsion feature. Also fixed bug with greater than 28 days.

* Removed comments and console.logs

* Create 2806.md

* Cleaned up code

* Hide's graph if no data, and hides average, last month or last year if no data.

* Apply suggestions from code review

Co-authored-by: default avatarNeil <55785687+carkom@users.noreply.github.com>

* Fixed spent MTD and last MTD. Added in all suggestions from carkom.

* Update 2806.md

* Added changes required by carkom #2

* Couple more fixes, only show graph if have data for last month (as requested by carkom)

* Removed console.log that was mistakenly added.

* removed useEffect

* Add files via upload

* Remove async function

* lint fix

* fixed carkom requests & added in fix for YAxis issues

* Fixed couple of mistakes. Removed Y Axis fix (new PR will be created)

* Cleanup code

* Fix mode buttons

* Removed console.log...

* Update showAverage Logic

* Update switch logic

default should be default for everyone other part of the graph.

* Add Math.abs

* lint fix

---------

Co-authored-by: default avatarNeil <55785687+carkom@users.noreply.github.com>
parent ebb9452b
No related branches found
No related tags found
No related merge requests found
......@@ -45,6 +45,7 @@ type CustomTooltipProps = {
payload?: PayloadItem[];
balanceTypeOp?: string;
thisMonth?: string;
lastYear?: string;
selection?: string;
};
......@@ -53,6 +54,7 @@ const CustomTooltip = ({
payload,
balanceTypeOp,
thisMonth,
lastYear,
selection,
}: CustomTooltipProps) => {
if (active && payload && payload.length) {
......@@ -82,21 +84,27 @@ const CustomTooltip = ({
</strong>
</div>
<div style={{ lineHeight: 1.5 }}>
{payload[0].payload.months[thisMonth].cumulative && (
{payload[0].payload.months[thisMonth].cumulative ? (
<AlignedText
left="This month:"
right={amountToCurrency(
payload[0].payload.months[thisMonth].cumulative * -1,
)}
/>
)}
) : null}
{['cumulative'].includes(balanceTypeOp) && (
<AlignedText
left={selection === 'average' ? 'Average' : 'Last month:'}
left={
selection === 'average'
? 'Average'
: selection === lastYear
? 'Last year'
: 'Last month'
}
right={amountToCurrency(comparison)}
/>
)}
{payload[0].payload.months[thisMonth].cumulative && (
{payload[0].payload.months[thisMonth].cumulative ? (
<AlignedText
left="Difference:"
right={amountToCurrency(
......@@ -104,7 +112,7 @@ const CustomTooltip = ({
comparison,
)}
/>
)}
) : null}
</div>
</div>
</div>
......@@ -129,7 +137,20 @@ export function SpendingGraph({
const balanceTypeOp = 'cumulative';
const thisMonth = monthUtils.currentMonth();
const lastMonth = monthUtils.subMonths(monthUtils.currentMonth(), 1);
const selection = mode.toLowerCase() === 'average' ? 'average' : lastMonth;
const lastYear = monthUtils.prevYear(monthUtils.currentMonth());
let selection;
switch (mode) {
case 'Average':
selection = 'average';
break;
case 'lastYear':
selection = lastYear;
break;
default:
selection = lastMonth;
break;
}
const thisMonthMax = data.intervalData.reduce((a, b) =>
a.months[thisMonth][balanceTypeOp] < b.months[thisMonth][balanceTypeOp]
? a
......@@ -139,11 +160,11 @@ export function SpendingGraph({
selection === 'average'
? data.intervalData[27].average
: data.intervalData.reduce((a, b) =>
a.months[lastMonth][balanceTypeOp] <
b.months[lastMonth][balanceTypeOp]
a.months[selection][balanceTypeOp] <
b.months[selection][balanceTypeOp]
? a
: b,
).months[lastMonth][balanceTypeOp];
).months[selection][balanceTypeOp];
const maxYAxis = selectionMax > thisMonthMax;
const dataMax = Math.max(
...data.intervalData.map(i => i.months[thisMonth].cumulative),
......@@ -233,6 +254,7 @@ export function SpendingGraph({
<CustomTooltip
balanceTypeOp={balanceTypeOp}
thisMonth={thisMonth}
lastYear={lastYear}
selection={selection}
/>
}
......
......@@ -38,7 +38,7 @@ export function Spending() {
} = useFilters<RuleConditionEntity>();
const [dataCheck, setDataCheck] = useState(false);
const [mode, setMode] = useState('Last month');
const [mode, setMode] = useState('lastMonth');
const getGraphData = useMemo(() => {
setDataCheck(false);
......@@ -57,15 +57,21 @@ export function Spending() {
if (!data) {
return null;
}
const showAverage =
data.intervalData[27].months[
monthUtils.subMonths(monthUtils.currentDay(), 3)
].daily !== 0;
Math.abs(
data.intervalData[27].months[
monthUtils.subMonths(monthUtils.currentDay(), 3)
].cumulative,
) > 0;
const todayDay =
monthUtils.getDay(monthUtils.currentDay()) - 1 >= 28
? 27
: monthUtils.getDay(monthUtils.currentDay()) - 1;
const showLastYear = Math.abs(data.intervalData[27].lastYear) > 0;
const showLastMonth = Math.abs(data.intervalData[27].lastMonth) > 0;
return (
<Page
header={
......@@ -171,30 +177,40 @@ export function Spending() {
marginBottom: 5,
}}
>
<AlignedText
left={<Block>Spent MTD:</Block>}
right={
<Text>
<PrivacyFilter blurIntensity={5}>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].thisMonth),
)}
</PrivacyFilter>
</Text>
}
/>
<AlignedText
left={<Block>Spent Last MTD:</Block>}
right={
<Text>
<PrivacyFilter blurIntensity={5}>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].lastMonth),
)}
</PrivacyFilter>
</Text>
}
/>
{showLastMonth && (
<View
style={{
...styles.mediumText,
fontWeight: 500,
marginBottom: 5,
}}
>
<AlignedText
left={<Block>Spent MTD:</Block>}
right={
<Text>
<PrivacyFilter blurIntensity={5}>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].thisMonth),
)}
</PrivacyFilter>
</Text>
}
/>
<AlignedText
left={<Block>Spent Last MTD:</Block>}
right={
<Text>
<PrivacyFilter blurIntensity={5}>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].lastMonth),
)}
</PrivacyFilter>
</Text>
}
/>
</View>
)}
{showAverage && (
<AlignedText
left={<Block>Spent Average MTD:</Block>}
......@@ -211,46 +227,66 @@ export function Spending() {
)}
</View>
</View>
<View
style={{
alignItems: 'center',
flexDirection: 'row',
}}
>
<Text
style={{
paddingRight: 10,
}}
>
Compare this month to:
</Text>
<ModeButton
selected={mode === 'Last month'}
onSelect={() => setMode('Last month')}
>
Last month
</ModeButton>
{showAverage && (
<ModeButton
selected={mode === 'Average'}
onSelect={() => setMode('Average')}
{!showLastMonth ? (
<View style={{ marginTop: 30 }}>
<h1>Additional data required to generate graph</h1>
<Paragraph>
Currently, there is insufficient data to display any
information regarding your spending. Please input
transactions from last month to enable graph visualization.
</Paragraph>
</View>
) : (
<>
<View
style={{
alignItems: 'center',
flexDirection: 'row',
}}
>
Average
</ModeButton>
)}
</View>
<Text
style={{
paddingRight: 10,
}}
>
Compare this month to:
</Text>
<ModeButton
selected={mode === 'lastMonth'}
onSelect={() => setMode('lastMonth')}
>
Last month
</ModeButton>
{showLastYear && (
<ModeButton
selected={mode === 'lastYear'}
onSelect={() => setMode('lastYear')}
>
Last year
</ModeButton>
)}
{showAverage && (
<ModeButton
selected={mode === 'Average'}
onSelect={() => setMode('Average')}
>
Average
</ModeButton>
)}
</View>
{dataCheck ? (
<SpendingGraph
style={{ flexGrow: 1 }}
compact={false}
data={data}
mode={mode}
/>
) : (
<LoadingIndicator message="Loading report..." />
{dataCheck ? (
<SpendingGraph
style={{ flexGrow: 1 }}
compact={false}
data={data}
mode={mode}
/>
) : (
<LoadingIndicator message="Loading report..." />
)}
</>
)}
{showAverage && (
<View style={{ marginTop: 30 }}>
<Paragraph>
......
......@@ -36,6 +36,7 @@ export function SpendingCard() {
data &&
data.intervalData[todayDay].lastMonth -
data.intervalData[todayDay].thisMonth;
const showLastMonth = data && Math.abs(data.intervalData[27].lastMonth) > 0;
return (
<ReportCard flex="1" to="/reports/spending">
......@@ -57,7 +58,7 @@ export function SpendingCard() {
end={monthUtils.currentMonth()}
/>
</View>
{data && (
{data && showLastMonth && (
<View style={{ textAlign: 'right' }}>
<Block
style={{
......@@ -80,8 +81,13 @@ export function SpendingCard() {
</View>
)}
</View>
{data ? (
{!showLastMonth ? (
<View style={{ padding: 5 }}>
<p style={{ margin: 0, textAlign: 'center' }}>
Additional data required to generate graph
</p>
</View>
) : data ? (
<SpendingGraph
style={{ flex: 1 }}
compact={true}
......@@ -89,7 +95,7 @@ export function SpendingCard() {
mode="lastMonth"
/>
) : (
<LoadingIndicator />
<LoadingIndicator message="Loading report..." />
)}
</View>
</ReportCard>
......
// @ts-strict-ignore
import keyBy from 'lodash/keyBy';
import { runQuery } from 'loot-core/src/client/query-helpers';
......@@ -35,6 +34,11 @@ export function createSpendingSpreadsheet({
setDataCheck,
}: createSpendingSpreadsheetProps) {
const [startDate, endDate] = getSpecificRange(3, null, 'Months');
const [lastYearStartDate, lastYearEndDate] = getSpecificRange(
12,
0,
'Months',
);
const interval = 'Daily';
return async (
......@@ -50,7 +54,7 @@ export function createSpendingSpreadsheet({
runQuery(
makeQuery(
'assets',
startDate,
lastYearStartDate,
endDate,
interval,
categories.list,
......@@ -61,7 +65,7 @@ export function createSpendingSpreadsheet({
runQuery(
makeQuery(
'debts',
startDate,
lastYearStartDate,
endDate,
interval,
categories.list,
......@@ -72,6 +76,9 @@ export function createSpendingSpreadsheet({
]);
const intervals = monthUtils.dayRangeInclusive(startDate, endDate);
intervals.push(
...monthUtils.dayRangeInclusive(lastYearStartDate, lastYearEndDate),
);
const days = [...Array(29).keys()]
.filter(f => f > 0)
.map(n => n.toString().padStart(2, '0'));
......@@ -85,6 +92,12 @@ export function createSpendingSpreadsheet({
return { month, perMonthAssets: 0, perMonthDebts: 0 };
});
months.unshift({
month: monthUtils.prevYear(monthUtils.currentMonth()),
perMonthAssets: 0,
perMonthDebts: 0,
});
const intervalData = days.map(day => {
let averageSum = 0;
let monthCount = 0;
......@@ -126,7 +139,10 @@ export function createSpendingSpreadsheet({
}
return null;
});
if (month.month !== monthUtils.currentMonth()) {
if (
month.month !== monthUtils.currentMonth() &&
month.month !== monthUtils.prevYear(monthUtils.currentMonth())
) {
averageSum += cumulativeAssets + cumulativeDebts;
monthCount += 1;
}
......@@ -165,8 +181,9 @@ export function createSpendingSpreadsheet({
months: indexedData,
day,
average: integerToAmount(averageSum) / monthCount,
thisMonth: dayData[3].cumulative,
lastMonth: dayData[2].cumulative,
thisMonth: dayData[4].cumulative,
lastMonth: dayData[3].cumulative,
lastYear: dayData[0].cumulative,
};
});
......
......@@ -49,6 +49,7 @@ export interface SpendingEntity {
average: number;
thisMonth: number;
lastMonth: number;
lastYear: number;
}[];
startDate?: string;
endDate?: string;
......
---
category: Features
authors: [Crazypkr1099]
---
Add Year Spending Comparison Feature
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment