Investment Roadmap: 5 display and data issues #17

Closed
opened 2026-05-04 13:05:32 +00:00 by casper-stevens · 3 comments
Member

Problem

The investment roadmap tab has several functional, UX, and data-integrity issues.


File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5164

The format string unconditionally renders an <a> tag for the company even when no company is linked to the transaction. When company is None, company_id resolves to an empty string, producing:

<a href="/c/{context}/companies/">-</a>

Fix: render plain text "-" when there is no company, only a link when company_id is non-empty.


2. Empty state: blank timeline when no investments exist

File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5274

When there are no investment transactions, the .timeline div renders completely empty. The user just sees an empty card body with no message.

Fix: show a friendly empty-state message when timeline_items is empty.


3. instruments loaded but never used

Handler: crates/hero_biz_ui/src/web/handlers/mod.rs ~line 5227
Template: crates/hero_biz_ui/src/web/templates/mod.rs struct InvestmentRoadmapTemplate

The handler fetches all instruments from the store and passes them into the template struct, but render() never references self.instruments. This is an unnecessary data-store round-trip.

Fix: remove the instruments field from InvestmentRoadmapTemplate and remove the load_all_instruments_for_space call from the handler.


4. Mixed-currency cumulative total is misleading

File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5113

cumulative_invested sums all investment amounts regardless of currency, but total_currency just stores the last transaction's currency. If investments exist in EUR and USD the displayed cumulative total and summary card are wrong.

Fix: group amounts by currency and either (a) display per-currency totals, or (b) skip multi-currency summing and show each currency separately in the summary card.


Files to Change

  • crates/hero_biz_ui/src/web/templates/mod.rs — issues 1, 2, 4
  • crates/hero_biz_ui/src/web/handlers/mod.rs — issue 3
## Problem The investment roadmap tab has several functional, UX, and data-integrity issues. --- ### 1. Broken company link when company is not found **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5164 The format string unconditionally renders an `<a>` tag for the company even when no company is linked to the transaction. When `company` is `None`, `company_id` resolves to an empty string, producing: ```html <a href="/c/{context}/companies/">-</a> ``` Fix: render plain text `"-"` when there is no company, only a link when `company_id` is non-empty. --- ### 2. Empty state: blank timeline when no investments exist **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5274 When there are no investment transactions, the `.timeline` div renders completely empty. The user just sees an empty card body with no message. Fix: show a friendly empty-state message when `timeline_items` is empty. --- ### 3. `instruments` loaded but never used **Handler:** `crates/hero_biz_ui/src/web/handlers/mod.rs` ~line 5227 **Template:** `crates/hero_biz_ui/src/web/templates/mod.rs` struct `InvestmentRoadmapTemplate` The handler fetches all instruments from the store and passes them into the template struct, but `render()` never references `self.instruments`. This is an unnecessary data-store round-trip. Fix: remove the `instruments` field from `InvestmentRoadmapTemplate` and remove the `load_all_instruments_for_space` call from the handler. --- ### 4. Mixed-currency cumulative total is misleading **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5113 `cumulative_invested` sums all investment amounts regardless of currency, but `total_currency` just stores the last transaction's currency. If investments exist in EUR and USD the displayed cumulative total and summary card are wrong. Fix: group amounts by currency and either (a) display per-currency totals, or (b) skip multi-currency summing and show each currency separately in the summary card. --- ## Files to Change - `crates/hero_biz_ui/src/web/templates/mod.rs` — issues 1, 2, 4 - `crates/hero_biz_ui/src/web/handlers/mod.rs` — issue 3
Author
Member

Implementation Spec for Issue #17

Objective

Fix four distinct bugs in the investment roadmap feature: a broken HTML anchor rendered even when no company is linked, a blank timeline when no investment transactions exist, dead code from an unused instruments field being fetched and stored, and a misleading mixed-currency cumulative total that collapses amounts across different currencies.


Files to Modify

  • crates/hero_biz_ui/src/web/templates/mod.rs — Issues 1, 2, 4
  • crates/hero_biz_ui/src/web/handlers/mod.rs — Issue 3

Requirements

  • When a transaction has no linked company (company is None), render the plain string "-" instead of <a href="/c/{context}/companies/">-</a>.
  • When timeline_items is empty after processing all transactions, render a visible empty-state message inside the .timeline div instead of leaving it blank.
  • Remove the instruments field from InvestmentRoadmapTemplate and remove the load_all_instruments_for_space call from the investment_roadmap handler.
  • Replace the single cumulative_invested: f64 + total_currency: String pair with a BTreeMap<String, f64> that accumulates amounts per currency key. In the "Total Invested" summary card, display per-currency lines derived from that map.
  • The per-currency cumulative shown on each timeline card's "Cumulative:" line must reflect only transactions in the same currency as the current transaction.

Implementation Plan

Step 1 — Remove instruments from InvestmentRoadmapTemplate (templates/mod.rs)

File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5169–5178

Remove the field pub instruments: Vec<Instrument>, from the struct. After the edit the struct body is:

pub struct InvestmentRoadmapTemplate {
    pub context: String,
    pub user_name: String,
    pub transactions: Vec<Transaction>,
    pub contracts: Vec<Contract>,
    pub companies: Vec<Company>,
    pub persons: Vec<Person>,
    pub base_path: String,
}

Dependencies: Must be done before Step 2.


Step 2 — Remove instruments fetch from the handler (handlers/mod.rs)

File: crates/hero_biz_ui/src/web/handlers/mod.rs ~line 5227–5231

Remove the load_all_instruments_for_space call and remove instruments, from the struct instantiation.

Dependencies: Step 1 must be complete first.


Step 3 — Fix broken company anchor when company is None (templates/mod.rs)

File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5244

Compute company_html before the format! call:

let company_html = match company {
    Some(c) => format!(
        r#"<a href="{bp}/c/{context}/companies/{id}">{name}</a>"#,
        id = c.id(),
        name = company_name,
    ),
    None => "-".to_string(),
};

Replace the anchor line in the format string with {company_html} and remove the company_id argument from the format! call.

Dependencies: None.


Step 4 — Multi-currency cumulative tracking (templates/mod.rs)

File: crates/hero_biz_ui/src/web/templates/mod.rs ~lines 5188–5370

  • Replace cumulative_invested: f64 + total_currency: String with cumulative_by_currency: BTreeMap<String, f64>.
  • In the loop: *cumulative_by_currency.entry(tx.currency.clone()).or_insert(0.0) += tx.amount;
  • For per-card "Cumulative:" line: use *cumulative_by_currency.get(&tx.currency).unwrap_or(&0.0).
  • Build total_invested_html joining per-currency "{amt:.0} {CUR}" lines with <br> and use it in the summary card.

Dependencies: None — independent of Steps 1–3.


Step 5 — Empty-state message when no investments exist (templates/mod.rs)

File: crates/hero_biz_ui/src/web/templates/mod.rs ~line 5350

Build timeline_html:

let timeline_html = if timeline_items.is_empty() {
    r#"<div class="text-center text-muted py-5">
        <i class="bi bi-graph-up fs-1 d-block mb-3"></i>
        <p class="mb-0">No investment transactions found.</p>
        <p class="small">Create a transaction of type <strong>Investment</strong> to see the roadmap.</p>
    </div>"#.to_string()
} else {
    timeline_items.join("\n")
};

Replace timeline_items = timeline_items.join("\n") argument with timeline_items = timeline_html.

Dependencies: None.


Acceptance Criteria

  • A transaction linked to a company renders a proper <a> link in the timeline card.
  • A transaction with no linked company renders plain text "-" with no anchor tag.
  • When there are zero investment transactions, the timeline div shows a visible message rather than being empty.
  • When all investments share a single currency, the "Total Invested" card shows {amount} {CURRENCY}.
  • When investments span multiple currencies, the "Total Invested" card shows one line per currency.
  • The per-card "Cumulative:" line reflects only the running total in the same currency as that transaction.
  • InvestmentRoadmapTemplate has no instruments field.
  • The investment_roadmap handler makes no call to load_all_instruments_for_space.
  • cargo check passes with no errors or new warnings.

Notes

  • Transaction.currency is a plain String (defaulting to "eur"). Use .to_uppercase() for display.
  • Use BTreeMap (not HashMap) for stable alphabetical iteration order.
  • The investment_dashboard handler also loads instruments — do NOT touch that handler; only investment_roadmap is in scope.
  • Steps 1 and 2 must be applied as an atomic pair.
  • Steps 3, 4, and 5 are independently applicable in any order.
## Implementation Spec for Issue #17 ### Objective Fix four distinct bugs in the investment roadmap feature: a broken HTML anchor rendered even when no company is linked, a blank timeline when no investment transactions exist, dead code from an unused `instruments` field being fetched and stored, and a misleading mixed-currency cumulative total that collapses amounts across different currencies. --- ### Files to Modify - `crates/hero_biz_ui/src/web/templates/mod.rs` — Issues 1, 2, 4 - `crates/hero_biz_ui/src/web/handlers/mod.rs` — Issue 3 --- ### Requirements - When a transaction has no linked company (`company` is `None`), render the plain string `"-"` instead of `<a href="/c/{context}/companies/">-</a>`. - When `timeline_items` is empty after processing all transactions, render a visible empty-state message inside the `.timeline` div instead of leaving it blank. - Remove the `instruments` field from `InvestmentRoadmapTemplate` and remove the `load_all_instruments_for_space` call from the `investment_roadmap` handler. - Replace the single `cumulative_invested: f64` + `total_currency: String` pair with a `BTreeMap<String, f64>` that accumulates amounts per currency key. In the "Total Invested" summary card, display per-currency lines derived from that map. - The per-currency cumulative shown on each timeline card's "Cumulative:" line must reflect only transactions in the same currency as the current transaction. --- ### Implementation Plan #### Step 1 — Remove `instruments` from `InvestmentRoadmapTemplate` (templates/mod.rs) **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5169–5178 Remove the field `pub instruments: Vec<Instrument>,` from the struct. After the edit the struct body is: ``` pub struct InvestmentRoadmapTemplate { pub context: String, pub user_name: String, pub transactions: Vec<Transaction>, pub contracts: Vec<Contract>, pub companies: Vec<Company>, pub persons: Vec<Person>, pub base_path: String, } ``` **Dependencies:** Must be done before Step 2. --- #### Step 2 — Remove `instruments` fetch from the handler (handlers/mod.rs) **File:** `crates/hero_biz_ui/src/web/handlers/mod.rs` ~line 5227–5231 Remove the `load_all_instruments_for_space` call and remove `instruments,` from the struct instantiation. **Dependencies:** Step 1 must be complete first. --- #### Step 3 — Fix broken company anchor when company is None (templates/mod.rs) **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5244 Compute `company_html` before the `format!` call: ```rust let company_html = match company { Some(c) => format!( r#"<a href="{bp}/c/{context}/companies/{id}">{name}</a>"#, id = c.id(), name = company_name, ), None => "-".to_string(), }; ``` Replace the anchor line in the format string with `{company_html}` and remove the `company_id` argument from the `format!` call. **Dependencies:** None. --- #### Step 4 — Multi-currency cumulative tracking (templates/mod.rs) **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~lines 5188–5370 - Replace `cumulative_invested: f64` + `total_currency: String` with `cumulative_by_currency: BTreeMap<String, f64>`. - In the loop: `*cumulative_by_currency.entry(tx.currency.clone()).or_insert(0.0) += tx.amount;` - For per-card "Cumulative:" line: use `*cumulative_by_currency.get(&tx.currency).unwrap_or(&0.0)`. - Build `total_invested_html` joining per-currency `"{amt:.0} {CUR}"` lines with `<br>` and use it in the summary card. **Dependencies:** None — independent of Steps 1–3. --- #### Step 5 — Empty-state message when no investments exist (templates/mod.rs) **File:** `crates/hero_biz_ui/src/web/templates/mod.rs` ~line 5350 Build `timeline_html`: ```rust let timeline_html = if timeline_items.is_empty() { r#"<div class="text-center text-muted py-5"> <i class="bi bi-graph-up fs-1 d-block mb-3"></i> <p class="mb-0">No investment transactions found.</p> <p class="small">Create a transaction of type <strong>Investment</strong> to see the roadmap.</p> </div>"#.to_string() } else { timeline_items.join("\n") }; ``` Replace `timeline_items = timeline_items.join("\n")` argument with `timeline_items = timeline_html`. **Dependencies:** None. --- ### Acceptance Criteria - [ ] A transaction linked to a company renders a proper `<a>` link in the timeline card. - [ ] A transaction with no linked company renders plain text `"-"` with no anchor tag. - [ ] When there are zero investment transactions, the timeline div shows a visible message rather than being empty. - [ ] When all investments share a single currency, the "Total Invested" card shows `{amount} {CURRENCY}`. - [ ] When investments span multiple currencies, the "Total Invested" card shows one line per currency. - [ ] The per-card "Cumulative:" line reflects only the running total in the same currency as that transaction. - [ ] `InvestmentRoadmapTemplate` has no `instruments` field. - [ ] The `investment_roadmap` handler makes no call to `load_all_instruments_for_space`. - [ ] `cargo check` passes with no errors or new warnings. --- ### Notes - `Transaction.currency` is a plain `String` (defaulting to `"eur"`). Use `.to_uppercase()` for display. - Use `BTreeMap` (not `HashMap`) for stable alphabetical iteration order. - The `investment_dashboard` handler also loads `instruments` — do NOT touch that handler; only `investment_roadmap` is in scope. - Steps 1 and 2 must be applied as an atomic pair. - Steps 3, 4, and 5 are independently applicable in any order.
Author
Member

Test Results

cargo check: passed

Tests

  • Total: 1
  • Passed: 1
  • Failed: 0

Details

All crates compiled cleanly. One unit test ran in hero_biz_ui:

test parser::tests::test_name_fix ... ok

The remaining crates (hero_biz, hero_biz_app, hero_biz_sdk) have no tests defined yet.

Branch: development_casper

## Test Results `cargo check`: passed ### Tests - Total: 1 - Passed: 1 - Failed: 0 ### Details All crates compiled cleanly. One unit test ran in `hero_biz_ui`: ``` test parser::tests::test_name_fix ... ok ``` The remaining crates (`hero_biz`, `hero_biz_app`, `hero_biz_sdk`) have no tests defined yet. Branch: `development_casper`
Author
Member

Implementation Complete

All four bugs in the investment roadmap tab have been fixed.

Changes Made

crates/hero_biz_ui/src/web/templates/mod.rs

  • Removed unused instruments field from InvestmentRoadmapTemplate struct
  • Fixed company link rendering: transactions with no linked company now show plain "-" instead of a broken empty anchor tag
  • Empty state: when there are no investment transactions, the timeline div now shows a friendly message instead of rendering blank
  • Multi-currency totals: replaced the single cumulative_invested + total_currency pair with a BTreeMap<String, f64> that tracks running totals per currency; the "Total Invested" summary card now displays one line per currency; per-card "Cumulative:" reflects only same-currency amounts

crates/hero_biz_ui/src/web/handlers/mod.rs

  • Removed the load_all_instruments_for_space call from the investment_roadmap handler (the instruments data was never used)

Test Results

  • cargo check: passed (all 4 workspace crates compiled cleanly)
  • cargo test: 1/1 passed, 0 failures
## Implementation Complete All four bugs in the investment roadmap tab have been fixed. ### Changes Made **`crates/hero_biz_ui/src/web/templates/mod.rs`** - Removed unused `instruments` field from `InvestmentRoadmapTemplate` struct - Fixed company link rendering: transactions with no linked company now show plain `"-"` instead of a broken empty anchor tag - Empty state: when there are no investment transactions, the timeline div now shows a friendly message instead of rendering blank - Multi-currency totals: replaced the single `cumulative_invested + total_currency` pair with a `BTreeMap<String, f64>` that tracks running totals per currency; the "Total Invested" summary card now displays one line per currency; per-card "Cumulative:" reflects only same-currency amounts **`crates/hero_biz_ui/src/web/handlers/mod.rs`** - Removed the `load_all_instruments_for_space` call from the `investment_roadmap` handler (the instruments data was never used) ### Test Results - `cargo check`: passed (all 4 workspace crates compiled cleanly) - `cargo test`: 1/1 passed, 0 failures
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_biz#17
No description provided.