From a5e9fe9cbb08b04526624fa6d1bf7363f009dfdf Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Sat, 18 Apr 2026 22:24:17 +1000 Subject: [PATCH] Update UI --- invest/services.py | 11 +- invest/template_views.py | 12 +- invest/templates/invest/dashboard.html | 160 ++++++++----------------- 3 files changed, 71 insertions(+), 112 deletions(-) diff --git a/invest/services.py b/invest/services.py index e58958d..13e304a 100644 --- a/invest/services.py +++ b/invest/services.py @@ -121,8 +121,15 @@ def get_weekly_overview() -> dict: week_change_pct = round((week_gain / last_week_total) * 100, 2) # Per-portfolio breakdown + _palette = [ + {'badge': 'bg-indigo-100 text-indigo-800', 'row': 'bg-indigo-50', 'border': 'border-indigo-200'}, + {'badge': 'bg-emerald-100 text-emerald-800', 'row': 'bg-emerald-50', 'border': 'border-emerald-200'}, + {'badge': 'bg-amber-100 text-amber-800', 'row': 'bg-amber-50', 'border': 'border-amber-200'}, + {'badge': 'bg-rose-100 text-rose-800', 'row': 'bg-rose-50', 'border': 'border-rose-200'}, + {'badge': 'bg-sky-100 text-sky-800', 'row': 'bg-sky-50', 'border': 'border-sky-200'}, + ] portfolio_rows = [] - for portfolio in Portfolio.objects.all(): + for idx, portfolio in enumerate(Portfolio.objects.all()): def _snap(date): if not date: return None @@ -145,6 +152,8 @@ def get_weekly_overview() -> dict: 'last_week_value': last_val, 'change': change, 'change_pct': change_pct, + 'position_count': portfolio.stocks.filter(quantity__gt=0).count(), + 'colors': _palette[idx % len(_palette)], }) return { diff --git a/invest/template_views.py b/invest/template_views.py index dadbfeb..98d5b56 100644 --- a/invest/template_views.py +++ b/invest/template_views.py @@ -19,10 +19,20 @@ def dashboard(request): fy_start = now.year if now.month >= 7 else now.year - 1 fy_label = f"FY {str(fy_start)[2:]}-{str(fy_start + 1)[2:]}" + all_holdings = get_all_holdings() + # Merge snapshot data (value, change, change_pct) into each holdings group + rows_by_id = {row['portfolio'].id: row for row in overview.get('portfolio_rows', [])} + for group in all_holdings: + row = rows_by_id.get(group['portfolio'].id, {}) + group['this_week_value'] = row.get('this_week_value') + group['change'] = row.get('change') + group['change_pct'] = row.get('change_pct') + group['position_count'] = row.get('position_count', len(group['holdings'])) + return render(request, 'invest/dashboard.html', { 'overview': overview, 'fy_label': fy_label, - 'all_holdings': get_all_holdings(), + 'all_holdings': all_holdings, 'chart_data_json': get_performance_chart_data() or 'null', }) diff --git a/invest/templates/invest/dashboard.html b/invest/templates/invest/dashboard.html index d7b958e..daeacf4 100644 --- a/invest/templates/invest/dashboard.html +++ b/invest/templates/invest/dashboard.html @@ -84,132 +84,72 @@ {% endif %} - -{% if overview.portfolio_rows %} -
-
-

Portfolio Breakdown

-
- - - - - - - - - - - - {% for row in overview.portfolio_rows %} - - - - - - - - {% endfor %} - - {% if overview.this_week_total is not None %} - - - - - - - - - - {% endif %} -
PortfolioThis WeekLast WeekChangeChange %
{{ row.portfolio.name }} - {% if row.this_week_value is not None %}${{ row.this_week_value|floatformat:0 }}{% else %}{% endif %} - - {% if row.last_week_value is not None %}${{ row.last_week_value|floatformat:0 }}{% else %}{% endif %} - - {% if row.change is not None %}{% if row.change >= 0 %}+{% endif %}${{ row.change|floatformat:0 }}{% else %}—{% endif %} - - {% if row.change_pct is not None %}{% if row.change_pct >= 0 %}+{% endif %}{{ row.change_pct|floatformat:2 }}%{% else %}—{% endif %} -
Total${{ overview.this_week_total|floatformat:0 }} - {% if overview.last_week_total is not None %}${{ overview.last_week_total|floatformat:0 }}{% else %}—{% endif %} - - {% if overview.week_gain is not None %}{% if overview.week_gain >= 0 %}+{% endif %}${{ overview.week_gain|floatformat:0 }}{% else %}—{% endif %} - - {% if overview.week_change_pct is not None %}{% if overview.week_change_pct >= 0 %}+{% endif %}{{ overview.week_change_pct|floatformat:2 }}%{% else %}—{% endif %} -
-
-{% else %} -
-

No portfolios yet.

-

Snapshots are captured every Saturday at 08:00.

-
-{% endif %} - -

+

Snapshots captured every Saturday 08:00 · Values in portfolio's quote currency

- + {% if all_holdings %} -
-

Live Holdings

-
- - -
+
{% for group in all_holdings %} - - {{ group.portfolio.name }} -  · ${{ group.total_value|floatformat:0 }} - - {% endfor %} -
- -
- - - - - - - - - - - - {% for group in all_holdings %} +
+ +
+
+

+ {{ group.portfolio.name }} +

+

+ {{ group.position_count }} position{{ group.position_count|pluralize }} + {% if overview.this_week_date %}· Last updated {{ overview.this_week_date|date:"j M Y" }}{% endif %} +

+
+
+

+ {% if group.this_week_value is not None %}${{ group.this_week_value|floatformat:0 }}{% else %}{% endif %} +

+ {% if group.change is not None %} +

+ {% if group.change >= 0 %}+{% endif %}${{ group.change|floatformat:0 }} + ({% if group.change_pct >= 0 %}+{% endif %}{{ group.change_pct|floatformat:1 }}%) +

+ {% else %} +

No prior snapshot

+ {% endif %} +
+
+ +
PortfolioStockQtyPriceValue
+ + + + + + + + + {% for stock in group.holdings %} - {% if forloop.first %} - - {% endif %} - - + - + {% endfor %} - - - - - - {% endfor %} - -
TickerQtyPriceMkt Value
+ - {{ group.portfolio.name }} + {{ stock.stock_code }} {{ stock.stock_code }}{{ stock.quantity|floatformat:2 }}{{ stock.quantity|floatformat:0 }} {% if stock.current_price %}${{ stock.current_price|floatformat:2 }}{% else %}{% endif %} ${{ stock.current_value|floatformat:0 }} + {% if stock.current_value %}${{ stock.current_value|floatformat:0 }}{% else %}{% endif %} +
- {{ group.portfolio.name }} total - ${{ group.total_value|floatformat:0 }}
+ + +
+ {% endfor %}
{% endif %}