Files
sure/app/views/investment_activity/_quick_edit_badge.html.erb
LPW 0c2026680c Improve investment activity labels UX and add convert-to-trade feature (#649)
* Add `investment_activity_label` to trades and enhance activity label handling

- Introduced `investment_activity_label` column to the `trades` table with a migration.
- Backfilled existing `trades` with activity labels based on quantity (`Buy`, `Sell`, or `Other`).
- Replaced `category_id` in trades with `investment_activity_label` for better alignment with transaction labels.
- Updated views and controllers to display and manage activity labels for trades.
- Added localized badge components for displaying and editing labels dynamically.
- Enhanced `PlaidAccount::Investments::TransactionsProcessor` to assign and process activity labels automatically.
- Added investment flows section to reports for tracking contributions and withdrawals.
- Refactored related tests and models for consistency and to ensure proper validation and filtering.

* Improve handling of `investment_activity_label`, trade type, and security selection in trades and transactions

- Refined label assignment logic in `trades_controller` to default to `Buy`/`Sell` based on transaction nature.
- Simplified security selection in `transactions_controller` by resolving via unique IDs or custom tickers.
- Streamlined UI for trade and transaction forms by updating dropdown options and label text.
- Enabled quick-edit badges to open `convert_to_trade` modal when applicable, enhancing flexibility.
- Adjusted tests and views to align with updated workflows and ensure consistent behavior.

* Improve handling of `investment_activity_label`, trade type, and security selection in trades and transactions

- Refined label assignment logic in `trades_controller` to default to `Buy`/`Sell` based on transaction nature.
- Simplified security selection in `transactions_controller` by resolving via unique IDs or custom tickers.
- Streamlined UI for trade and transaction forms by updating dropdown options and label text.
- Enabled quick-edit badges to open `convert_to_trade` modal when applicable, enhancing flexibility.
- Adjusted tests and views to align with updated workflows and ensure consistent behavior.

* Improve handling of `investment_activity_label`, trade type, and security selection in trades and transactions

- Refined label assignment logic in `trades_controller` to default to `Buy`/`Sell` based on transaction nature.
- Simplified security selection in `transactions_controller` by resolving via unique IDs or custom tickers.
- Streamlined UI for trade and transaction forms by updating dropdown options and label text.
- Enabled quick-edit badges to open `convert_to_trade` modal when applicable, enhancing flexibility.
- Adjusted tests and views to align with updated workflows and ensure consistent behavior.

* Add safeguard for `dropdownTarget` existence in quick edit controller

- Prevent errors by ensuring `dropdownTarget` is present before toggling its visibility.

* Fix undefined method 'category' for Trade on mobile view

Trade model uses investment_activity_label, not category. The upstream
merge introduced a call to trade.category which doesn't exist. Use the
activity label badge on mobile instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix activity label logic for zero/blank quantity and sell inference

- Return `nil` for blank or zero quantity in `investment_activity_label_for`.
- Correct `is_sell` logic to use the amount’s sign properly in `transactions_controller`.

* Fix i18n key paths in transactions controller for convert_to_trade

- Update flash message translations to use full i18n paths.
- Use `BigDecimal` for quantity and price calculations to improve precision.

---------

Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 21:04:10 +01:00

96 lines
3.9 KiB
Plaintext

<%# locals: (entry:, entryable:) %>
<%
label = entryable.investment_activity_label
has_label = label.present?
# Build the correct URL based on entryable type
update_url = entryable.is_a?(Transaction) ? transaction_path(entry) : trade_path(entry)
# Color mapping for different investment activity labels using design system tokens
color = if has_label
case label
when "Buy"
"var(--color-blue-500)"
when "Sell"
"var(--color-red-500)"
when "Dividend", "Interest"
"var(--color-green-500)"
when "Contribution"
"var(--color-violet-500)"
when "Withdrawal"
"var(--color-orange-500)"
when "Fee"
"var(--color-gray-500)"
when "Transfer", "Sweep In", "Sweep Out", "Exchange"
"var(--color-gray-500)"
when "Reinvestment"
"var(--color-blue-500)"
else
"var(--color-gray-500)" # for "Other"
end
else
"var(--color-gray-400)" # slightly lighter for empty state
end
activity_labels = entryable.is_a?(Trade) ? Trade::ACTIVITY_LABELS : Transaction::ACTIVITY_LABELS
entryable_type = entryable.is_a?(Trade) ? "Trade" : "Transaction"
convert_url = entryable.is_a?(Transaction) ? convert_to_trade_transaction_path(entryable) : nil
%>
<div class="relative"
data-controller="activity-label-quick-edit"
data-activity-label-quick-edit-url-value="<%= update_url %>"
data-activity-label-quick-edit-entryable-id-value="<%= entryable.id %>"
data-activity-label-quick-edit-current-label-value="<%= label %>"
data-activity-label-quick-edit-entryable-type-value="<%= entryable_type %>"
<% if convert_url %>
data-activity-label-quick-edit-convert-url-value="<%= convert_url %>"
<% end %>>
<button type="button"
class="inline-flex items-center gap-1 text-xs font-medium rounded-full px-2.5 py-1 cursor-pointer hover:opacity-80 transition-opacity"
style="<% if has_label %>
background-color: color-mix(in oklab, <%= color %> 15%, transparent);
border: 1px solid color-mix(in oklab, <%= color %> 25%, transparent);
color: <%= color %>;
<% else %>
background-color: var(--color-surface-inset);
border: 1px solid var(--color-border-secondary);
color: var(--color-text-secondary);
<% end %>"
data-action="click->activity-label-quick-edit#toggle"
data-activity-label-quick-edit-target="badge"
title="<%= has_label ? t("transactions.transaction.activity_type_tooltip") : t("transactions.show.activity_type") %>">
<% if has_label %>
<%= label %>
<% else %>
<%= icon "tag", size: "xs", color: "current" %>
<span><%= t("transactions.show.activity_type") %></span>
<% end %>
<%= icon "chevron-down", size: "xs", color: "current" %>
</button>
<!-- Dropdown menu -->
<div class="hidden absolute right-0 z-50 mt-1 w-44 rounded-lg border border-primary bg-container shadow-lg"
data-activity-label-quick-edit-target="dropdown">
<div class="py-1 max-h-64 overflow-y-auto">
<% if has_label %>
<button type="button"
class="w-full text-left px-3 py-1.5 text-sm text-secondary hover:bg-surface-inset transition-colors border-b border-primary"
data-action="click->activity-label-quick-edit#select"
data-label="">
<span class="italic"><%= t("transactions.form.none") %></span>
</button>
<% end %>
<% activity_labels.each do |activity_label| %>
<button type="button"
class="w-full text-left px-3 py-1.5 text-sm text-primary hover:bg-surface-inset transition-colors <%= activity_label == label ? "font-semibold bg-surface-inset" : "" %>"
data-action="click->activity-label-quick-edit#select"
data-label="<%= activity_label %>">
<%= activity_label %>
</button>
<% end %>
</div>
</div>
</div>