mirror of
https://github.com/we-promise/sure.git
synced 2026-04-20 04:24:06 +00:00
Add SnapTrade brokerage integration with full trade history support (#737)
* Introduce SnapTrade integration with models, migrations, views, and activity processing logic. * Refactor SnapTrade activities processing: improve activity fetching flow, handle pending states, and update UI elements for enhanced user feedback. * Update Brakeman ignore file to include intentional redirect for SnapTrade OAuth portal. * Refactor SnapTrade models, views, and processing logic: add currency extraction helper, improve pending state handling, optimize migration checks, and enhance user feedback in UI. * Remove encryption for SnapTrade `snaptrade_user_id`, as it is an identifier, not a secret. * Introduce `SnaptradeConnectionCleanupJob` to asynchronously handle SnapTrade connection cleanup and improve i18n for SnapTrade item status messages. * Update SnapTrade encryption: make `snaptrade_user_secret` non-deterministic to enhance security. --------- Signed-off-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: luckyPipewrench <luckypipewrench@proton.me> Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
98
app/views/settings/providers/_snaptrade_panel.html.erb
Normal file
98
app/views/settings/providers/_snaptrade_panel.html.erb
Normal file
@@ -0,0 +1,98 @@
|
||||
<div class="space-y-4">
|
||||
<div class="prose prose-sm text-secondary">
|
||||
<p><%= t("providers.snaptrade.description") %></p>
|
||||
|
||||
<p class="text-primary font-medium"><%= t("providers.snaptrade.setup_title") %></p>
|
||||
<ol>
|
||||
<li><%= t("providers.snaptrade.step_1_html") %></li>
|
||||
<li><%= t("providers.snaptrade.step_2") %></li>
|
||||
<li><%= t("providers.snaptrade.step_3") %></li>
|
||||
<li><%= t("providers.snaptrade.step_4") %></li>
|
||||
</ol>
|
||||
|
||||
<p class="text-warning text-sm"><%= icon("alert-triangle", class: "inline-block w-4 h-4 mr-1") %><%= t("providers.snaptrade.free_tier_warning") %></p>
|
||||
</div>
|
||||
|
||||
<% error_msg = local_assigns[:error_message] || @error_message %>
|
||||
<% if error_msg.present? %>
|
||||
<div class="p-2 rounded-md bg-destructive/10 text-destructive text-sm overflow-hidden">
|
||||
<p class="line-clamp-3" title="<%= error_msg %>"><%= error_msg %></p>
|
||||
</div>
|
||||
<% 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"),
|
||||
class: "btn btn--primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% items = local_assigns[:snaptrade_items] || @snaptrade_items || Current.family.snaptrade_items.where.not(client_id: [nil, ""]) %>
|
||||
|
||||
<div class="border-t border-primary pt-4 mt-4">
|
||||
<% if items&.any? %>
|
||||
<% item = items.first %>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<% if item.user_registered? %>
|
||||
<div class="w-2 h-2 bg-success rounded-full"></div>
|
||||
<p class="text-sm text-secondary">
|
||||
<% if item.snaptrade_accounts.any? %>
|
||||
<%= 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 %>
|
||||
<% else %>
|
||||
<%= t("providers.snaptrade.status_ready") %>
|
||||
<% end %>
|
||||
</p>
|
||||
<% else %>
|
||||
<div class="w-2 h-2 bg-warning rounded-full"></div>
|
||||
<p class="text-sm text-secondary"><%= t("providers.snaptrade.status_needs_registration") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if item.snaptrade_accounts.any? %>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= link_to t("providers.snaptrade.setup_accounts_button"),
|
||||
setup_accounts_snaptrade_item_path(item),
|
||||
class: "btn btn--secondary btn--sm" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if item.snaptrade_accounts.any? %>
|
||||
<div class="mt-3 text-sm text-secondary">
|
||||
<p><%= t("providers.snaptrade.connected_brokerages") %> <%= item.brokerage_summary %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-2 h-2 bg-gray-400 rounded-full"></div>
|
||||
<p class="text-sm text-secondary"><%= t("providers.snaptrade.status_not_configured") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,4 +53,10 @@
|
||||
<%= render "settings/providers/coinbase_panel" %>
|
||||
</turbo-frame>
|
||||
<% end %>
|
||||
|
||||
<%= settings_section title: "SnapTrade (beta)", collapsible: true, open: false do %>
|
||||
<turbo-frame id="snaptrade-providers-panel">
|
||||
<%= render "settings/providers/snaptrade_panel" %>
|
||||
</turbo-frame>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user