From 2eadfe99a512cdcb732eac8b9dc1ba1b1c997012 Mon Sep 17 00:00:00 2001 From: Herculino Trotta Date: Sat, 19 Apr 2025 00:00:31 -0300 Subject: [PATCH] feat(insights:category-overview): select if you want to view table or bar charts, defaults to table --- app/apps/insights/views.py | 8 +- .../fragments/category_overview/index.html | 432 ++++++++++-------- 2 files changed, 236 insertions(+), 204 deletions(-) diff --git a/app/apps/insights/views.py b/app/apps/insights/views.py index 1495d05..b6ee79b 100644 --- a/app/apps/insights/views.py +++ b/app/apps/insights/views.py @@ -168,6 +168,12 @@ def category_sum_by_currency(request): @login_required @require_http_methods(["GET"]) def category_overview(request): + view_type = request.session.get("insights_category_explorer_view_type", "table") + + if "view_type" in request.GET: + view_type = request.GET["view_type"] + request.session["insights_category_explorer_view_type"] = view_type + # Get filtered transactions transactions = get_transactions(request, include_silent=True) @@ -178,7 +184,7 @@ def category_overview(request): return render( request, "insights/fragments/category_overview/index.html", - {"total_table": total_table}, + {"total_table": total_table, "view_type": view_type}, ) diff --git a/app/templates/insights/fragments/category_overview/index.html b/app/templates/insights/fragments/category_overview/index.html index 360b2f9..6fbff4b 100644 --- a/app/templates/insights/fragments/category_overview/index.html +++ b/app/templates/insights/fragments/category_overview/index.html @@ -1,226 +1,252 @@ {% load i18n %}
+ hx-include="#picker-form, #picker-type, #view-type"> +
+
+ + + + + +
+
{% if total_table %} -
- - - - - - - - - - - {% for category in total_table.values %} + {% if view_type == "table" %} +
+
{% trans 'Category' %}{% trans 'Income' %}{% trans 'Expense' %}{% trans 'Total' %}
+ - - - - + + + + - {% endfor %} - -
{% if category.name %}{{ category.name }}{% else %}{% trans 'Uncategorized' %}{% endif %} - {% for currency in category.currencies.values %} - {% if currency.total_income != 0 %} - - {% else %} -
-
- {% endif %} - {% endfor %} -
- {% for currency in category.currencies.values %} - {% if currency.total_expense != 0 %} - - {% else %} -
-
- {% endif %} - {% endfor %} -
- {% for currency in category.currencies.values %} - {% if currency.total_final != 0 %} - - {% else %} -
-
- {% endif %} - {% endfor %} -
{% trans 'Category' %}{% trans 'Income' %}{% trans 'Expense' %}{% trans 'Total' %}
-
- -
-
- + + + {% for category in total_table.values %} + + {% if category.name %}{{ category.name }}{% else %}{% trans 'Uncategorized' %}{% endif %} + + {% for currency in category.currencies.values %} + {% if currency.total_income != 0 %} + + {% else %} +
-
+ {% endif %} + {% endfor %} + + + {% for currency in category.currencies.values %} + {% if currency.total_expense != 0 %} + + {% else %} +
-
+ {% endif %} + {% endfor %} + + + {% for currency in category.currencies.values %} + {% if currency.total_final != 0 %} + + {% else %} +
-
+ {% endif %} + {% endfor %} + + + {% endfor %} + +
-
- {{ total_table|json_script:"categoryOverviewData" }} + {% elif view_type == "bars" %} +
+
+ +
+
- + let formattedValue = ''; + try { + // Use Intl.NumberFormat for ALL values, configured with locale and exact decimal places + formattedValue = new Intl.NumberFormat(undefined, { + minimumFractionDigits: details.decimal_places, + maximumFractionDigits: details.decimal_places, + // Do NOT use style: 'currency' here, as we add prefix/suffix manually + }).format(value); + } catch (e) { + formattedValue = value.toFixed(details.decimal_places); + } + // Return label with currency name and formatted value including prefix/suffix + return `${details.prefix}${formattedValue}${details.suffix}`; + } + } + }, + legend: { + position: 'top', + } + }, + scales: { + x: { + stacked: true, + type: 'linear', + title: { + display: true, + text: '{% trans 'Final Total' %}' + }, + ticks: { + // Format ticks using the detected locale + callback: function (value, index, ticks) { + return value.toLocaleString(); + } + } + }, + y: { + stacked: true, + title: { + display: false, + text: '{% trans 'Category' %}' + } + } + } + } + }); + } + + {% endif %} {% else %} {% endif %}