Skip to content
This repository has been archived by the owner on Jun 5, 2024. It is now read-only.

Commit

Permalink
Updates Year insights information
Browse files Browse the repository at this point in the history
  • Loading branch information
inoda committed Oct 23, 2021
1 parent 55fa383 commit 87c9f30
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 34 deletions.
6 changes: 5 additions & 1 deletion app/assets/stylesheets/grid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
margin-top: 10px;
}

.mt-50-sm {
margin-top: 50px;
}

@media (min-width: 750px) {
.column, .columns {
margin-left: 4%;
Expand Down Expand Up @@ -79,7 +83,7 @@
display: flex !important;
}

.mt-10-sm {
.mt-10-sm, .mt-50-sm {
margin-top: 0;
}
}
Expand Down
15 changes: 15 additions & 0 deletions app/assets/stylesheets/pages/insights.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,18 @@
box-shadow: 2px 2px #d6d4d4;
margin-top: 30px;
}

#insights .totals table {
width: 100%;
border-collapse: collapse;

td {
border: 1px solid #d3d3d3;
text-align: left;
padding: 15px 10px;
}

td.total {
background-color: #e7e7e7;
}
}
38 changes: 32 additions & 6 deletions app/controllers/api/v1/reports_controller.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
module Api; module V1
class ReportsController < BaseController
def year
results = ActiveRecord::Base.connection.execute(%{
select categories.name AS category, to_char(date_trunc('month', paid_at), 'Mon') AS month, sum(expenses.amount)/100.0 AS amount
total = ActiveRecord::Base.connection.execute(%{
select sum(expenses.amount) as amount
from expenses
where paid_at >= '#{params[:year].to_i}-01-01'
and paid_at < '#{params[:year].to_i + 1}-01-01'
}).first['amount']

category_percentages = ActiveRecord::Base.connection.execute(%{
select categories.name AS category, sum(expenses.amount) / #{total.to_f} AS percentage
from expenses
join categories on expenses.category_id = categories.id
where paid_at >= '#{params[:year].to_i}-01-01'
and paid_at < '#{params[:year].to_i + 1}-01-01'
group by month, categories.name;
group by categories.id
order by percentage;
})

total = ActiveRecord::Base.connection.execute(%{
select sum(expenses.amount) as amount
category_totals = ActiveRecord::Base.connection.execute(%{
select categories.name AS category, sum(expenses.amount) AS amount
from expenses
join categories on expenses.category_id = categories.id
where paid_at >= '#{params[:year].to_i}-01-01'
and paid_at < '#{params[:year].to_i + 1}-01-01'
group by categories.id
order by amount;
})

category_amounts_by_month = ActiveRecord::Base.connection.execute(%{
select categories.name AS category, to_char(date_trunc('month', paid_at), 'Mon') AS month, sum(expenses.amount) AS amount
from expenses
join categories on expenses.category_id = categories.id
where paid_at >= '#{params[:year].to_i}-01-01'
and paid_at < '#{params[:year].to_i + 1}-01-01'
group by month, categories.id;
})

render json: { results: results, total: total.first['amount'], categories: Category.all.select(:id, :name, :color).order(:name) }
render json: {
category_percentages: category_percentages,
category_totals: category_totals,
category_amounts_by_month: category_amounts_by_month,
total: total,
categories: Category.all.select(:id, :name, :color).order(:name)
}
end

def month
Expand Down
16 changes: 8 additions & 8 deletions app/javascript/components/insights/Month.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ const Month = ({ availableMonths }) => {
</div>

<div className="row">
<div className="six columns">
<div className="month flex flex-space-between">
<b>Total spend</b>
<h2>
{Numerics.centsToDollars(spend)}
</h2>
</div>
</div>
<div className="six columns">
{!goal && (
<a className="month flex flex-space-between" href="/">
Expand All @@ -70,14 +78,6 @@ const Month = ({ availableMonths }) => {
</div>
)}
</div>
<div className="six columns">
<div className="month flex flex-space-between">
<b>Total spend</b>
<h2>
{Numerics.centsToDollars(spend)}
</h2>
</div>
</div>
</div>

<div className="month">
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/components/insights/PieChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const PieChart = ({ data, labels, colors }) => {
},
tooltips: {
callbacks: {
label: t => `${labels[t.index]}: $${Numerics.commify(data[t.index].toFixed(2))}`,
label: t => `${labels[t.index]}: ${data[t.index]}%`,
},
},
},
Expand Down
55 changes: 37 additions & 18 deletions app/javascript/components/insights/Year.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Numerics } from '../../helpers/main';
const Year = ({ availableYears }) => {
const [year, setYear] = useState(availableYears[0]);
const [yearTotal, setYearTotal] = useState(0);
const [categoryTotals, setCategoryTotals] = useState([]);
const barChartLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const [barChartData, setBarChartData] = useState([]);
const [pieChartData, setPieChartData] = useState({
Expand All @@ -22,28 +23,27 @@ const Year = ({ availableYears }) => {
useEffect(() => {
Reports.year({ year }).then(
(resp) => {
const barChartDatasets = [];
resp.categories.forEach((category) => {
const dataPoints = [];
barChartLabels.forEach((mon) => {
const spendForCategoryAndMonth = resp.results.find((monthData) => monthData.month == mon && monthData.category == category.name);
dataPoints.push(spendForCategoryAndMonth ? spendForCategoryAndMonth.amount : 0);
const barChartDatasets = resp.categories.map((c) => {
const dataPoints = barChartLabels.map((mon) => {
const amount = resp.category_amounts_by_month.find((a) => a.month == mon && a.category == c.name)?.amount;
return Numerics.centsToFloat(amount || 0);
});
barChartDatasets.push({ label: category.name, data: dataPoints, backgroundColor: category.color });
return { label: c.name, data: dataPoints, backgroundColor: c.color };
});

const pieChartDatasets = [];
const pieChartLabels = [];
const pieChartColors = [];
resp.categories.forEach((category) => {
pieChartLabels.push(category.name);
pieChartColors.push(category.color);
const totalForCategory = resp.results.filter((monthData) => monthData.category === category.name).reduce((a, b) => a + parseFloat(b.amount), 0);
pieChartDatasets.push(totalForCategory);
resp.categories.forEach((c) => {
pieChartLabels.push(c.name);
pieChartColors.push(c.color);
const percentage = resp.category_percentages.find((p) => p.category === c.name)?.percentage;
pieChartDatasets.push(Numerics.floatToPercent(percentage || 0));
});

setBarChartData(barChartDatasets);
setPieChartData({ data: pieChartDatasets, colors: pieChartColors, labels: pieChartLabels });
setCategoryTotals(resp.category_totals);
setYearTotal(resp.total);
},
() => { Alerts.genericError(); },
Expand All @@ -53,9 +53,6 @@ const Year = ({ availableYears }) => {
return (
<div>
<div className="flex flex-space-between mb-30">
<b>
Total spend: {Numerics.centsToDollars(yearTotal)}
</b>
<div className="input-group inline">
<select value={year} onChange={handleYearChange}>
{availableYears.map(yr => <option key={yr} value={yr}>{yr}</option>)}
Expand All @@ -64,11 +61,33 @@ const Year = ({ availableYears }) => {
</div>

<div className="chart-container">
<BarChart data={barChartData} labels={barChartLabels} />
<BarChart data={barChartData} labels={barChartLabels} hideLegend />
</div>

<div className="chart-container mt-50">
<PieChart data={pieChartData.data} labels={pieChartData.labels} colors={pieChartData.colors} />
<div className="row row-flex flex mt-100">
<div className="six columns">
<div className="chart-container">
<PieChart data={pieChartData.data} labels={pieChartData.labels} colors={pieChartData.colors} />
</div>
</div>

<div className="totals six columns mt-50-sm">
<table>
<tbody>
{categoryTotals.map(t => (
<tr key={t.category} >
<td>{t.category}</td>
<td>{Numerics.centsToDollars(t.amount)}</td>
</tr>
))}

<tr>
<td><b>Total</b></td>
<td className="total"><b>{Numerics.centsToDollars(yearTotal)}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
);
Expand Down
24 changes: 24 additions & 0 deletions app/javascript/helpers/numerics.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@ const Numerics = {
}
},

centsToFloat(value) {
if (value == null || value == undefined) { return 0; }

try {
return (value / 100).toFixed(2);
} catch (error) {
// eslint-disable-next-line no-console
console.error(value, error);
return value;
}
},

floatToPercent(value) {
if (value == null || value == undefined) { return 0; }

try {
return (value * 100).toFixed(2);
} catch (error) {
// eslint-disable-next-line no-console
console.error(value, error);
return value;
}
},

commify(value) {
if (value == null || value == undefined) { return ''; }
// This accounts for more than 3 digits after a decimal. We don't want commas there.
Expand Down

0 comments on commit 87c9f30

Please sign in to comment.