Files
sure/app/views/settings/providers/_snaptrade_panel.html.erb
Guillem Arias Fauste 8de14ed2a5 feat(design-system): DS::Disclosure :inline variant + migrate indexa_capital + snaptrade panels (#1715 §6) (#1858)
* feat(design-system): add :inline variant + migrate indexa_capital + snaptrade panels

Adds an `:inline` variant to `DS::Disclosure` for plain text-link-style
toggles that have no surface, no padding, no shadow — the disclosure
reads as a clickable summary text + revealed content, nothing more.

Use case: "Alternative auth" form section toggle in the Indexa Capital
provider panel; "Manage connections" lazy-loaded toggle in the
Snaptrade provider panel. Both were the last raw-`<details>` callsites
in `app/views/settings/providers/`.

Migrations:

- `_indexa_capital_panel.html.erb` — single inline `<details>` revealing
  username / document / password form fields under an "Alternative auth"
  summary text.
- `_snaptrade_panel.html.erb` — lazy-load `<details>` with
  `data-controller="lazy-load"` etc. The new `tag.details ... **opts`
  forwarding from #1857 lets the Stimulus controller attrs flow
  through cleanly via DS::Disclosure's `data:` keyword.

Chevron rotation on snaptrade gets the standard
`motion-safe:transition-transform motion-safe:duration-150` treatment
(was `transition-transform` without the motion-safe gate).

Variant summary now:

| Variant | Details surface | Use case |
|---|---|---|
| `:default` | none / bg-surface summary | inline expander inside parent card |
| `:card` | `bg-container shadow-border-xs rounded-xl p-4` | provider rows, settings sections |
| `:card_inset` | `bg-surface-inset rounded-xl p-4` | inset sub-panels |
| `:inline` | no surface | text-link-style toggles |

* fix(review): guard variant.to_sym against nil in DS::Disclosure

CodeRabbit on #1858 flagged that `variant: nil` crashed with
`NoMethodError` at `variant.to_sym` before the explicit `VARIANTS`
check could run. Use safe navigation (`variant&.to_sym`) so nil
falls through to the validation, and inspect `@variant` in the
error message so nil / non-symbol inputs render readably.

Verified manually via runner: `DS::Disclosure.new(variant: nil)` now
raises `ArgumentError: Invalid variant: nil. Must be one of
[:default, :card, :card_inset, :inline]`.
2026-05-22 02:14:44 +02:00

99 lines
4.3 KiB
Plaintext

<div class="space-y-4">
<%= render DS::Alert.new(message: t("providers.snaptrade.free_tier_warning"), variant: :warning) %>
<%= render "settings/providers/setup_steps",
steps: [
t("providers.snaptrade.step_1_html").html_safe,
t("providers.snaptrade.step_2"),
t("providers.snaptrade.step_3"),
t("providers.snaptrade.step_4")
] %>
<% error_msg = local_assigns[:error_message] || @error_message %>
<% if error_msg.present? %>
<%= render DS::Alert.new(message: error_msg, variant: :error) %>
<% end %>
<%
snaptrade_item = Current.family.snaptrade_items.first_or_initialize(name: "SnapTrade Connection")
is_new_record = snaptrade_item.new_record?
is_configured = snaptrade_item.persisted? && snaptrade_item.credentials_configured?
is_registered = snaptrade_item.persisted? && snaptrade_item.user_registered?
%>
<%= styled_form_with model: snaptrade_item,
url: is_new_record ? snaptrade_items_path : snaptrade_item_path(snaptrade_item),
scope: :snaptrade_item,
method: is_new_record ? :post : :patch,
data: { turbo: true },
class: "space-y-3" do |form| %>
<%= form.text_field :client_id,
label: t("providers.snaptrade.client_id_label"),
placeholder: is_new_record ? t("providers.snaptrade.client_id_placeholder") : t("providers.snaptrade.client_id_update_placeholder"),
type: :password %>
<%= form.text_field :consumer_key,
label: t("providers.snaptrade.consumer_key_label"),
placeholder: is_new_record ? t("providers.snaptrade.consumer_key_placeholder") : t("providers.snaptrade.consumer_key_update_placeholder"),
type: :password %>
<div class="flex justify-end">
<%= form.submit is_new_record ? t("providers.snaptrade.save_button") : t("providers.snaptrade.update_button") %>
</div>
<% end %>
<% items = local_assigns[:snaptrade_items] || @snaptrade_items || Current.family.snaptrade_items.where.not(client_id: [nil, ""]) %>
<% if items&.any? %>
<% item = items.first %>
<% unless item.user_registered? %>
<div class="flex items-center gap-2 border-t border-primary pt-4 mt-4">
<span class="w-2 h-2 bg-warning rounded-full"></span>
<p class="text-sm text-secondary"><%= t("providers.snaptrade.status_needs_registration") %></p>
</div>
<% end %>
<% end %>
<% if items&.any? && items.first.user_registered? %>
<% item = items.first %>
<div class="border-t border-primary pt-4 mt-4">
<%= render DS::Disclosure.new(
variant: :inline,
data: {
controller: "lazy-load",
action: "toggle->lazy-load#toggled",
lazy_load_url_value: connections_snaptrade_item_path(item),
lazy_load_auto_open_param_value: "manage"
}
) do |disclosure| %>
<% disclosure.with_summary_content do %>
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<p class="text-sm text-secondary">
<%= t("providers.snaptrade.status_connected", count: item.snaptrade_accounts.count) %>
<% if item.unlinked_accounts_count > 0 %>
<span class="text-warning">(<%= t("providers.snaptrade.needs_setup", count: item.unlinked_accounts_count) %>)</span>
<% end %>
</p>
</div>
<span class="flex items-center gap-1 text-sm text-secondary hover:text-primary">
<%= t("providers.snaptrade.manage_connections") %>
<%= icon "chevron-right", class: "w-3 h-3 group-open:rotate-90 motion-safe:transition-transform motion-safe:duration-150" %>
</span>
</div>
<% end %>
<div class="mt-3 space-y-3" data-lazy-load-target="content">
<div data-lazy-load-target="loading" class="flex items-center gap-2 text-sm text-secondary py-2">
<%= icon "loader-2", class: "w-4 h-4 animate-spin" %>
<%= t("providers.snaptrade.loading_connections") %>
</div>
<div data-lazy-load-target="frame">
</div>
</div>
<% end %>
</div>
<% end %>
</div>