mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 15:35:22 +02:00
Button updates
This commit is contained in:
parent
fdbfa14779
commit
a3fea6164d
40 changed files with 285 additions and 207 deletions
|
@ -3,7 +3,7 @@
|
|||
class ButtonComponent < ViewComponent::Base
|
||||
VARIANTS = {
|
||||
primary: {
|
||||
bg: "bg-gray-900 theme-dark:bg-white hover:bg-gray-800 theme-dark:hover:bg-gray-50 disabled:bg-gray-500 theme-dark:disabled:bg-gray-400",
|
||||
bg: "bg-inverse hover:bg-inverse-hover disabled:bg-gray-500 theme-dark:disabled:bg-gray-400",
|
||||
text: "text-white theme-dark:text-gray-900",
|
||||
icon: "fg-inverse"
|
||||
},
|
||||
|
@ -12,6 +12,11 @@ class ButtonComponent < ViewComponent::Base
|
|||
text: "text-gray-900 theme-dark:text-white",
|
||||
icon: "fg-primary"
|
||||
},
|
||||
destructive: {
|
||||
bg: "bg-red-500 theme-dark:bg-red-400 hover:bg-red-600 theme-dark:hover:bg-red-500 disabled:bg-red-200 theme-dark:disabled:bg-red-600",
|
||||
text: "text-white theme-dark:text-white",
|
||||
icon: "fg-white"
|
||||
},
|
||||
outline: {
|
||||
bg: "bg-transparent hover:bg-gray-100 theme-dark:hover:bg-gray-700",
|
||||
text: "text-gray-900 theme-dark:text-white",
|
||||
|
@ -42,6 +47,11 @@ class ButtonComponent < ViewComponent::Base
|
|||
bg: "bg-transparent hover:bg-gray-100 theme-dark:hover:bg-gray-700 rounded-lg",
|
||||
text: "text-secondary",
|
||||
icon: "fg-gray"
|
||||
},
|
||||
icon_inverse: {
|
||||
bg: "bg-inverse hover:bg-inverse-hover rounded-lg",
|
||||
text: "fg-inverse",
|
||||
icon: "fg-inverse"
|
||||
}
|
||||
}.freeze
|
||||
|
||||
|
@ -71,7 +81,7 @@ class ButtonComponent < ViewComponent::Base
|
|||
@variant = (options.delete(:variant) || "primary").underscore.to_sym
|
||||
@size = (options.delete(:size) || :md).to_sym
|
||||
@href = options.delete(:href)
|
||||
@method = options.delete(:method)
|
||||
@method = options.delete(:method) || :get
|
||||
@leading_icon = options.delete(:leading_icon)
|
||||
@trailing_icon = options.delete(:trailing_icon)
|
||||
@icon = options.delete(:icon)
|
||||
|
@ -82,11 +92,12 @@ class ButtonComponent < ViewComponent::Base
|
|||
end
|
||||
|
||||
def wrapper_tag(&block)
|
||||
if @href && @method
|
||||
if @href && @method != :get
|
||||
button_to @href, class: container_classes, method: @method, **@options, &block
|
||||
elsif @href
|
||||
link_to @href, class: container_classes, **@options, &block
|
||||
else
|
||||
html_tag = @href ? "a" : "button"
|
||||
content_tag(html_tag, class: container_classes, href: @href, **@options, &block)
|
||||
content_tag :button, class: container_classes, **@options, &block
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -106,7 +117,7 @@ class ButtonComponent < ViewComponent::Base
|
|||
end
|
||||
|
||||
def icon_only?
|
||||
@variant == :icon
|
||||
@variant == :icon || @variant == :icon_inverse
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -115,7 +126,7 @@ class ButtonComponent < ViewComponent::Base
|
|||
"inline-flex items-center gap-1",
|
||||
@full_width ? "w-full" : nil,
|
||||
@left_align ? "justify-start" : "justify-center",
|
||||
@variant == :icon ? size_meta[:icon_container] : size_meta[:container],
|
||||
icon_only? ? size_meta[:icon_container] : size_meta[:container],
|
||||
variant_meta[:bg],
|
||||
variant_meta.dig(:border),
|
||||
@extra_classes
|
||||
|
|
|
@ -1,31 +1,26 @@
|
|||
class MenuItemComponent < ViewComponent::Base
|
||||
erb_template <<~ERB
|
||||
<%= wrapper do %>
|
||||
<%= render IconComponent.new(@icon, variant: destructive? ? "destructive" : "default") %>
|
||||
<% if @icon %>
|
||||
<%= render IconComponent.new(@icon, variant: destructive? ? "destructive" : "default") %>
|
||||
<% end %>
|
||||
<%= tag.span(@text, class: text_classes) %>
|
||||
<% end %>
|
||||
ERB
|
||||
|
||||
VARIANTS = {
|
||||
link: {},
|
||||
action: {}
|
||||
}
|
||||
|
||||
def initialize(text:, href:, variant: "link", method: :post, icon: nil, data: {})
|
||||
def initialize(text:, href:, method: :get, icon: nil, data: {})
|
||||
@text = text
|
||||
@icon = icon
|
||||
@href = href
|
||||
@variant = variant.to_sym
|
||||
@method = method
|
||||
@method = method.to_sym
|
||||
@data = data
|
||||
end
|
||||
|
||||
def wrapper(&block)
|
||||
case @variant
|
||||
when :link
|
||||
link_to @href, data: @data, class: container_classes, &block
|
||||
when :action
|
||||
if @method.in?([ :post, :patch, :delete ])
|
||||
button_to @href, method: @method, data: @data, class: container_classes, &block
|
||||
else
|
||||
link_to @href, data: @data, class: container_classes, &block
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class StyledFormBuilder < ActionView::Helpers::FormBuilder
|
|||
opts = options.dup
|
||||
opts[:data] = { turbo_submits_with: "Submitting..." }.merge(opts[:data] || {})
|
||||
|
||||
@template.render(ButtonComponent.new(text: value, **opts))
|
||||
@template.render(ButtonComponent.new(text: value, full_width: true, **opts))
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -5,29 +5,23 @@
|
|||
<div class="flex items-center justify-between mb-4">
|
||||
<%= tag.h2 t(".title"), class: "font-medium text-lg" %>
|
||||
<% unless @account.plaid_account_id.present? %>
|
||||
<div data-controller="menu" data-testid="activity-menu">
|
||||
<%= render ButtonComponent.new(text: "New", variant: "secondary", leading_icon: "plus", data: { menu_target: "button" }) %>
|
||||
<%= render MenuComponent.new(variant: "button") do |menu| %>
|
||||
<% menu.with_button(text: "New", variant: "secondary", leading_icon: "plus") %>
|
||||
|
||||
<div data-menu-target="content" class="z-10 hidden bg-container rounded-lg border border-alpha-black-25 shadow-xs p-1">
|
||||
<%= render ButtonComponent.new(
|
||||
<% menu.with_item(
|
||||
text: "New balance",
|
||||
variant: "ghost",
|
||||
full_width: true,
|
||||
left_align: true,
|
||||
leading_icon: "circle-dollar-sign",
|
||||
href: new_valuation_path(account_id: @account.id),
|
||||
data: { turbo_frame: :modal }) %>
|
||||
icon: "circle-dollar-sign",
|
||||
href: new_valuation_path(account_id: @account.id), data: { turbo_frame: :modal }) %>
|
||||
|
||||
<% unless @account.crypto? %>
|
||||
<%= link_to @account.investment? ? new_trade_path(account_id: @account.id) : new_transaction_path(account_id: @account.id), data: { turbo_frame: :modal }, class: "btn btn--primary flex items-center justify-center gap-2 rounded-full md:rounded-lg w-9 h-9 md:w-auto md:h-auto" do %>
|
||||
<span class="flex items-center justify-center">
|
||||
<%= lucide_icon("credit-card", class: "text-secondary w-5 h-5") %>
|
||||
</span>
|
||||
<%= tag.span t(".new_transaction"), class: "text-sm md:block" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% unless @account.crypto? %>
|
||||
<% href = @account.investment? ? new_trade_path(account_id: @account.id) : new_transaction_path(account_id: @account.id) %>
|
||||
<% menu.with_item(
|
||||
text: "New transaction",
|
||||
icon: "credit-card",
|
||||
href: href,
|
||||
data: { turbo_frame: :modal }) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
href: account_path(account),
|
||||
method: :delete,
|
||||
icon: "trash-2",
|
||||
variant: "action",
|
||||
data: { turbo_frame: :_top, turbo_confirm: {
|
||||
title: t(".confirm_title"),
|
||||
body: t(".confirm_body_html"),
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<div id="<%= dom_id(budget, :confirm_button) %>">
|
||||
<% if budget.allocations_valid? %>
|
||||
<%= link_to "Confirm",
|
||||
budget_path(budget),
|
||||
class: "block btn btn--primary w-full text-center" %>
|
||||
<% else %>
|
||||
<span class="block btn btn--secondary w-full text-center text-subdued cursor-not-allowed">
|
||||
Confirm
|
||||
</span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Confirm",
|
||||
variant: "primary",
|
||||
full_width: true,
|
||||
href: budget_path(budget),
|
||||
disabled: !budget.allocations_valid?
|
||||
) %>
|
||||
</div>
|
||||
|
|
|
@ -6,12 +6,19 @@
|
|||
</p>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= button_to "Use defaults (recommended)", bootstrap_categories_path, class: "btn btn--primary" %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Use defaults (recommended)",
|
||||
href: bootstrap_categories_path,
|
||||
method: :post
|
||||
) %>
|
||||
|
||||
<%= link_to new_category_path, class: "btn btn--outline flex items-center gap-1", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span>New category</span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "New category",
|
||||
variant: "outline",
|
||||
leading_icon: "plus",
|
||||
href: new_category_path,
|
||||
data: { turbo_frame: "modal" }
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -133,14 +133,17 @@
|
|||
<% end %>
|
||||
</ul>
|
||||
|
||||
<%= link_to "View all category transactions",
|
||||
transactions_path(q: {
|
||||
categories: [@budget_category.name],
|
||||
start_date: @budget.start_date,
|
||||
end_date: @budget.end_date
|
||||
}),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "block text-center btn btn--outline w-full" %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "View all category transactions",
|
||||
variant: "outline",
|
||||
full_width: true,
|
||||
href: transactions_path(q: {
|
||||
categories: [@budget_category.name],
|
||||
start_date: @budget.start_date,
|
||||
end_date: @budget.end_date
|
||||
}),
|
||||
data: { turbo_frame: :_top }
|
||||
) %>
|
||||
<% else %>
|
||||
<p class="text-secondary text-sm mb-4">
|
||||
No transactions found for this budget period.
|
||||
|
|
|
@ -8,24 +8,28 @@
|
|||
<span>Spent</span>
|
||||
</div>
|
||||
|
||||
<div class="text-3xl font-medium <%= budget.available_to_spend.negative? ? "text-red-500" : "text-primary" %>">
|
||||
<div class="mb-2 text-3xl font-medium <%= budget.available_to_spend.negative? ? "text-red-500" : "text-primary" %>">
|
||||
<%= format_money(budget.actual_spending_money) %>
|
||||
</div>
|
||||
|
||||
<%= link_to edit_budget_path(budget), class: "btn btn--secondary flex items-center gap-1 mt-2" do %>
|
||||
<span class="text-primary font-medium">
|
||||
of <%= format_money(budget.budgeted_spending_money) %>
|
||||
</span>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary hover:text-gray-600" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "of #{budget.budgeted_spending_money.format}",
|
||||
variant: "secondary",
|
||||
trailing_icon: "pencil",
|
||||
size: "sm",
|
||||
href: edit_budget_path(budget)
|
||||
) %>
|
||||
<% else %>
|
||||
<div class="text-subdued text-3xl mb-2">
|
||||
<span><%= format_money Money.new(0, budget.currency || budget.family.currency) %></span>
|
||||
</div>
|
||||
<%= link_to edit_budget_path(budget), class: "flex items-center gap-2 btn btn--primary" do %>
|
||||
<%= lucide_icon "plus", class: "w-4 h-4 text-white" %>
|
||||
New budget
|
||||
<% end %>
|
||||
|
||||
<%= render ButtonComponent.new(
|
||||
text: "New budget",
|
||||
size: "sm",
|
||||
leading_icon: "plus",
|
||||
href: edit_budget_path(budget)
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
@ -41,11 +45,13 @@
|
|||
<%= format_money(bc.actual_spending_money) %>
|
||||
</p>
|
||||
|
||||
<%= link_to budget_budget_categories_path(budget), class: "btn btn--secondary flex items-center gap-1" do %>
|
||||
<span>of <%= format_money(bc.budgeted_spending_money, precision: 0) %></span>
|
||||
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary shrink-0" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "of #{bc.budgeted_spending_money.format(precision: 0)}",
|
||||
variant: "secondary",
|
||||
trailing_icon: "pencil",
|
||||
size: "sm",
|
||||
href: budget_budget_categories_path(budget)
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
<% if @budget.current? %>
|
||||
<span class="border border-secondary text-primary text-sm font-medium px-3 py-2 rounded-lg">Today</span>
|
||||
<% else %>
|
||||
<%= link_to "Today", budget_path(Budget.date_to_param(Date.current)), class: "btn btn--outline" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Today",
|
||||
variant: "outline",
|
||||
href: budget_path(Budget.date_to_param(Date.current)),
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
<%= lucide_icon "alert-triangle", class: "w-6 h-6 text-red-500" %>
|
||||
<p class="text-secondary text-sm text-center">You have over-allocated your budget. Please fix your allocations.</p>
|
||||
|
||||
<%= link_to budget_budget_categories_path(budget), class: "btn btn--secondary flex items-center gap-1" do %>
|
||||
<span class="text-primary font-medium">
|
||||
Fix allocations
|
||||
</span>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary hover:text-gray-600" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Fix allocations",
|
||||
variant: "secondary",
|
||||
size: "sm",
|
||||
trailing_icon: "pencil",
|
||||
href: budget_budget_categories_path(budget)
|
||||
) %>
|
||||
</div>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<% param_key = Budget.date_to_param(date) %>
|
||||
|
||||
<% if Budget.budget_date_valid?(date, family: family) %>
|
||||
<%= link_to month_name, budget_path(param_key), data: { turbo_frame: "_top" }, class: "btn btn--ghost" %>
|
||||
<%= render ButtonComponent.new(variant: "ghost", text: month_name, href: budget_path(param_key), data: { turbo_frame: :_top }) %>
|
||||
<% else %>
|
||||
<span class="px-3 py-2 text-subdued rounded-md"><%= month_name %></span>
|
||||
<% end %>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= f.submit "Continue", class: "btn btn--primary w-full" %>
|
||||
<%= f.submit "Continue" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -54,10 +54,12 @@
|
|||
<h2 class="text-lg font-medium">Categories</h2>
|
||||
|
||||
<% if @budget.initialized? %>
|
||||
<%= link_to budget_budget_categories_path(@budget), class: "btn btn--secondary flex items-center gap-2" do %>
|
||||
<%= icon "settings-2", color: "gray" %>
|
||||
<span>Edit</span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Edit",
|
||||
variant: "secondary",
|
||||
leading_icon: "settings-2",
|
||||
href: budget_budget_categories_path(@budget)
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -2,18 +2,29 @@
|
|||
<h1 class="text-primary text-xl font-medium"><%= t(".categories") %></h1>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= contextual_menu do %>
|
||||
<%= contextual_menu_destructive_item "Delete all", destroy_all_categories_path, turbo_confirm: {
|
||||
title: "Delete all categories?",
|
||||
body: "All of your transactions will become uncategorized and this cannot be undone.",
|
||||
accept: "Delete all categories",
|
||||
} %>
|
||||
<%= render MenuComponent.new do |menu| %>
|
||||
<% menu.with_item(
|
||||
text: "Delete all",
|
||||
href: destroy_all_categories_path,
|
||||
method: :delete,
|
||||
icon: "trash-2",
|
||||
data: {
|
||||
turbo_confirm: {
|
||||
title: "Delete all categories?",
|
||||
body: "All of your transactions will become uncategorized and this cannot be undone.",
|
||||
accept: "Delete all categories",
|
||||
}
|
||||
}
|
||||
) %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to new_category_path, class: "btn btn--primary flex items-center gap-1 justify-center", data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon "plus", class: "w-5 h-5" %>
|
||||
<p><%= t(".new") %></p>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".new"),
|
||||
variant: "primary",
|
||||
leading_icon: "plus",
|
||||
href: new_category_path,
|
||||
data: { turbo_frame: :modal }
|
||||
) %>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
@ -33,12 +44,19 @@
|
|||
<div class="text-center flex flex-col items-center max-w-[500px]">
|
||||
<p class="text-sm text-secondary mb-4"><%= t(".empty") %></p>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= button_to t(".bootstrap"), bootstrap_categories_path, class: "btn btn--primary" %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".bootstrap"),
|
||||
href: bootstrap_categories_path,
|
||||
method: :post
|
||||
) %>
|
||||
|
||||
<%= link_to new_category_path, class: "btn btn--outline flex items-center gap-1", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span><%= t(".new") %></span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".new"),
|
||||
variant: "outline",
|
||||
leading_icon: "plus",
|
||||
href: new_category_path,
|
||||
data: { turbo_frame: :modal }
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -22,7 +22,13 @@
|
|||
<div class="flex justify-center items-center py-12">
|
||||
<div class="text-center flex flex-col items-center max-w-[500px]">
|
||||
<p class="text-sm text-secondary font-normal mb-4"><%= t(".empty") %></p>
|
||||
<%= button_to t(".bootstrap"), bootstrap_categories_path, class: "btn btn--outline", data: { turbo_frame: :_top } %>
|
||||
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".bootstrap"),
|
||||
variant: "outline",
|
||||
href: bootstrap_categories_path,
|
||||
method: :post,
|
||||
data: { turbo_frame: :_top }) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
<div class="flex items-center justify-between gap-2">
|
||||
<p class="text-xs text-red-500">Failed to generate response. Please try again.</p>
|
||||
|
||||
<%= button_to retry_chat_path(chat), method: :post, class: "btn btn--primary" do %>
|
||||
<span>Retry</span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Retry",
|
||||
variant: "primary",
|
||||
href: retry_chat_path(chat),
|
||||
method: :post
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -27,5 +27,10 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-center py-8">
|
||||
<%= link_to "Edit account details", edit_credit_card_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Edit account details",
|
||||
variant: "ghost",
|
||||
href: edit_credit_card_path(account),
|
||||
data: { turbo_frame: :modal }
|
||||
) %>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<header class="flex items-center justify-between">
|
||||
<h1 class="text-primary text-xl font-medium">Merchants</h1>
|
||||
|
||||
<%= link_to new_family_merchant_path, class: "btn btn--primary flex items-center gap-2", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<p class="text-sm font-medium">New merchant</p>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "New merchant",
|
||||
href: new_family_merchant_path,
|
||||
data: { turbo_frame: "modal" }
|
||||
) %>
|
||||
</header>
|
||||
|
||||
<div class="bg-container shadow-border-xs rounded-xl p-4">
|
||||
|
|
|
@ -17,7 +17,12 @@
|
|||
<p class="text-green-500 text-sm md:text-base">Your data has been cleaned</p>
|
||||
</div>
|
||||
|
||||
<%= link_to "Next step", import_confirm_path(@import), class: "btn btn--primary w-full md:w-auto" %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Next step",
|
||||
href: import_confirm_path(@import),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "w-full md:w-auto"
|
||||
) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="bg-container border border-tertiary rounded-lg p-3 flex flex-col md:flex-row items-start md:items-center justify-between gap-3 md:gap-0">
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
<%= form.select :amount_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Balance" }, required: true %>
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Default", label: "Currency" } %>
|
||||
|
||||
<%= form.submit "Apply configuration", class: "w-full btn btn--primary", disabled: import.complete? %>
|
||||
<%= form.submit "Apply configuration", disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -29,5 +29,5 @@
|
|||
<%= form.select :category_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Category (optional)" }, disabled: import.complete? %>
|
||||
<%= form.select :tags_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Tags (optional)" }, disabled: import.complete? %>
|
||||
|
||||
<%= form.submit "Apply configuration", class: "w-full btn btn--primary", disabled: import.complete? %>
|
||||
<%= form.submit "Apply configuration", disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -36,5 +36,5 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= form.submit "Apply configuration", class: "w-full btn btn--primary", disabled: import.complete? %>
|
||||
<%= form.submit "Apply configuration", disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -107,7 +107,5 @@
|
|||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Notes" } %>
|
||||
|
||||
<%= form.submit "Apply configuration",
|
||||
class: "w-full btn btn--primary",
|
||||
disabled: import.complete? %>
|
||||
<%= form.submit "Apply configuration", disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<p class="text-sm text-secondary">We found a configuration from a previous import for this account. Would you like to apply it to this import?</p>
|
||||
|
||||
<div class="mt-4 flex gap-2 items-center">
|
||||
<%= link_to "Manually configure", import_configuration_path(@import), class: "btn btn--outline" %>
|
||||
<%= button_to "Apply template", apply_template_import_path(@import), class: "btn btn--primary", method: :put, data: { turbo_frame: :_top } %>
|
||||
<%= ButtonComponent.new(text: "Manually configure", href: import_configuration_path(@import), variant: "outline") %>
|
||||
<%= ButtonComponent.new(text: "Apply template", href: apply_template_import_path(@import), method: :put, data: { turbo_frame: :_top }) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,18 +8,19 @@
|
|||
<% if import.requires_account? %>
|
||||
<div class="w-full max-w-full overflow-hidden mb-4">
|
||||
<div class="overflow-x-auto">
|
||||
<div class="flex items-center justify-between p-4 gap-4 text-secondary bg-red-100 border border-red-200 rounded-lg w-[650px] min-w-0">
|
||||
<div class="flex items-center justify-between p-4 gap-4 text-secondary bg-red-100 border border-red-200 rounded-lg w-[650px] min-w-0 mx-auto">
|
||||
<%= tag.p t(".no_accounts"), class: "text-sm" %>
|
||||
<%= link_to t(".create_account"), new_account_path(return_to: import_confirm_path(import)), class: "btn btn--primary whitespace-nowrap", data: { turbo_frame: :modal } %>
|
||||
|
||||
<%= render ButtonComponent.new(text: "Create account", href: new_account_path(return_to: import_confirm_path(import)), data: { turbo_frame: :modal }) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% elsif import.has_unassigned_account? %>
|
||||
<div class="w-full max-w-full overflow-hidden mb-4">
|
||||
<div class="overflow-x-auto">
|
||||
<div class="flex items-center justify-between p-4 gap-4 text-secondary bg-yellow-100 border border-yellow-200 rounded-lg w-[650px] min-w-0">
|
||||
<div class="flex items-center justify-between p-4 gap-4 text-secondary bg-yellow-100 border border-yellow-200 rounded-lg w-[650px] min-w-0 mx-auto">
|
||||
<%= tag.p t(".unassigned_account"), class: "text-sm" %>
|
||||
<%= link_to t(".create_account"), new_account_path(return_to: import_confirm_path(import)), class: "btn btn--primary whitespace-nowrap", data: { turbo_frame: :modal } %>
|
||||
<%= render ButtonComponent.new(text: t(".create_account"), href: new_account_path(return_to: import_confirm_path(import)), data: { turbo_frame: :modal }) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,7 +30,7 @@
|
|||
<div class="space-y-4 w-full max-w-full">
|
||||
<div class="w-full max-w-full overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<div class="bg-container-inset rounded-xl p-1 space-y-1 w-[650px] min-w-0">
|
||||
<div class="bg-container-inset rounded-xl p-1 space-y-1 w-[650px] min-w-0 mx-auto">
|
||||
<div class="grid grid-cols-3 gap-2 text-xs font-medium text-secondary uppercase px-5 py-3">
|
||||
<p><%= t(".csv_mapping_label", mapping: mapping_label(mapping_class)) %></p>
|
||||
<p><%= t(".maybe_mapping_label", mapping: mapping_label(mapping_class)) %></p>
|
||||
|
@ -48,10 +49,7 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-center w-full">
|
||||
<%= link_to is_last_step ? import_path(import) : url_for(step: step_idx + 2), class: "btn btn--primary w-full md:w-36 flex items-center justify-between gap-2" do %>
|
||||
<span>Next</span>
|
||||
<%= lucide_icon "arrow-right", class: "w-5 h-5" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(text: "Next", href: is_last_step ? import_path(import) : url_for(step: step_idx + 2), trailing_icon: "arrow-right", class: "w-full md:w-auto") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
<div class="flex justify-center items-center py-20">
|
||||
<div class="text-center flex flex-col items-center max-w-[300px] gap-4">
|
||||
<p class="text-primary mb-1 font-medium text-sm"><%= t(".message") %></p>
|
||||
<%= link_to new_import_path, class: "btn btn--primary flex items-center gap-2", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span><%= t(".new") %></span>
|
||||
<% end %>
|
||||
|
||||
<%= render ButtonComponent.new(text: t(".new"), href: new_import_path, leading_icon: "plus", data: { turbo_frame: "modal" }) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
<p class="text-sm text-secondary">Please check that your file format, for any errors and that all required fields are filled, then come back and try again.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= button_to "Try again", publish_import_path(import), class: "btn btn--primary text-center w-full" %>
|
||||
</div>
|
||||
<%= render ButtonComponent.new(text: "Try again", href: publish_import_path(import), method: :post) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<%= link_to "Check status", import_path(import), class: "block btn btn--primary text-center w-full" %>
|
||||
<%= link_to "Back to dashboard", root_path, class: "block btn btn--secondary text-center w-full" %>
|
||||
<%= render ButtonComponent.new(text: "Check status", href: import_path(import)) %>
|
||||
<%= render ButtonComponent.new(text: "Back to dashboard", href: root_path, variant: "secondary") %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -35,5 +35,5 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<%= button_to "Publish import", publish_import_path(import), class: "btn btn--primary w-full" %>
|
||||
<%= ButtonComponent.new(text: "Publish import", href: publish_import_path(import), method: :post) %>
|
||||
</div>
|
||||
|
|
|
@ -11,8 +11,11 @@
|
|||
<p class="text-sm text-secondary">Please try again or contact support.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= button_to "Try again", revert_import_path(import), class: "btn btn--primary text-center w-full" %>
|
||||
</div>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Try again",
|
||||
full_width: true,
|
||||
href: revert_import_path(import),
|
||||
method: :post
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
<p class="text-sm text-secondary">Your imported data has been successfully added to the app and is now ready for use.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= link_to "Back to dashboard", root_path, class: "block btn btn--primary text-center w-full" %>
|
||||
</div>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Back to dashboard",
|
||||
full_width: true,
|
||||
href: root_path
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-medium text-primary"><%= t(".title") %></h1>
|
||||
|
||||
<%= link_to new_import_path, class: "btn btn--primary flex items-center gap-2", data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span><%= t(".new") %></span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "New import",
|
||||
href: new_import_path,
|
||||
leading_icon: "plus",
|
||||
data: { turbo_frame: :modal }
|
||||
) %>
|
||||
</div>
|
||||
|
||||
<div class="bg-container shadow-border-xs rounded-xl p-4">
|
||||
|
|
|
@ -45,5 +45,10 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-center py-8">
|
||||
<%= link_to "Edit loan details", edit_loan_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: "Edit loan details",
|
||||
variant: "ghost",
|
||||
href: edit_loan_path(account),
|
||||
data: { turbo_frame: :modal }
|
||||
) %>
|
||||
</div>
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<%= link_to t(".continue"), settings_security_path, class: "w-full btn btn--primary" %>
|
||||
</div>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".continue"),
|
||||
href: settings_security_path,
|
||||
full_width: true
|
||||
) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
placeholder: t(".code_placeholder") %>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<%= f.submit t(".verify_button"), class: "btn btn--primary" %>
|
||||
<%= f.submit t(".verify_button") %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
<%= tag.h1 t(".title"), class: "text-3xl font-medium mb-2" %>
|
||||
<%= tag.p t(".message"), class: "text-sm text-secondary mb-6" %>
|
||||
|
||||
<%= link_to t(".setup"), profile_onboarding_path, class: "block flex justify-center items-center btn btn--primary w-full" %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".setup"),
|
||||
href: profile_onboarding_path,
|
||||
full_width: true
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
<p class="text-gray-500">Here's what's happening with your finances</p>
|
||||
</div>
|
||||
|
||||
<%= link_to new_account_path(step: "method_select", classification: "asset"),
|
||||
class: "btn btn--primary flex items-center justify-center gap-2 rounded-full w-9 h-9 md:hidden",
|
||||
data: { turbo_frame: "modal" } do %>
|
||||
<span class="flex items-center justify-center">
|
||||
<%= lucide_icon("plus", class: "size-5") %>
|
||||
</span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
variant: "icon-inverse",
|
||||
icon: "plus",
|
||||
href: new_account_path(step: "method_select", classification: "asset"),
|
||||
data: { turbo_frame: "modal" },
|
||||
class: "rounded-full! md:hidden"
|
||||
) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
<p class="text-secondary"><%= t(".no_account_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<%= link_to new_account_path, class: "btn btn--primary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<span><%= t(".new_account") %></span>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".new_account"),
|
||||
href: new_account_path,
|
||||
leading_icon: "plus",
|
||||
data: { turbo_frame: "modal" }
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -50,49 +50,61 @@
|
|||
<% if plaid_item.requires_update? %>
|
||||
<% begin %>
|
||||
<% link_token = plaid_item.get_update_link_token(webhooks_url: plaid_webhooks_url(plaid_item.plaid_region), redirect_url: accounts_url) %>
|
||||
<button
|
||||
data-controller="plaid"
|
||||
data-action="plaid#open"
|
||||
data-plaid-region-value="<%= plaid_item.plaid_region %>"
|
||||
data-plaid-link-token-value="<%= link_token %>"
|
||||
data-plaid-is-update-value="true"
|
||||
data-plaid-item-id-value="<%= plaid_item.id %>"
|
||||
class="btn btn--secondary flex items-center gap-2">
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4" %>
|
||||
<%= tag.span t(".update") %>
|
||||
</button>
|
||||
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".update"),
|
||||
leading_icon: "refresh-cw",
|
||||
variant: "secondary",
|
||||
data: {
|
||||
controller: "plaid",
|
||||
action: "plaid#open",
|
||||
plaid_region_value: plaid_item.plaid_region,
|
||||
plaid_link_token_value: link_token,
|
||||
plaid_is_update_value: true,
|
||||
plaid_item_id_value: plaid_item.id
|
||||
}
|
||||
) %>
|
||||
<% rescue PlaidItem::PlaidConnectionLostError %>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="text-amber-500 flex items-center gap-1">
|
||||
<%= lucide_icon "alert-triangle", class: "w-4 h-4" %>
|
||||
<%= tag.span t(".connection_lost") %>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-secondary"><%= t(".connection_lost_description") %></p>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= button_to plaid_item_path(plaid_item),
|
||||
method: :delete,
|
||||
class: "btn btn--danger flex items-center gap-2",
|
||||
data: {
|
||||
turbo_confirm: {
|
||||
title: t(".confirm_title"),
|
||||
body: t(".confirm_body"),
|
||||
accept: t(".confirm_accept")
|
||||
}
|
||||
} do %>
|
||||
<%= lucide_icon "trash-2", class: "w-4 h-4" %>
|
||||
<%= tag.span t(".delete") %>
|
||||
<% end %>
|
||||
<%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-2" do %>
|
||||
<%= lucide_icon "plus", class: "w-4 h-4" %>
|
||||
<%= tag.span t(".add_new") %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".delete"),
|
||||
leading_icon: "trash-2",
|
||||
variant: "destructive",
|
||||
method: :delete,
|
||||
data: {
|
||||
turbo_confirm: {
|
||||
title: t(".confirm_title"),
|
||||
body: t(".confirm_body"),
|
||||
accept: t(".confirm_accept")
|
||||
}
|
||||
}
|
||||
) %>
|
||||
|
||||
<%= render ButtonComponent.new(
|
||||
text: t(".add_new"),
|
||||
leading_icon: "plus",
|
||||
variant: "secondary",
|
||||
href: new_account_path
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= button_to sync_plaid_item_path(plaid_item), disabled: plaid_item.syncing? || plaid_item.scheduled_for_deletion?, class: "disabled:text-subdued text-primary flex hover:text-gray-800 items-center text-sm font-medium hover:underline" do %>
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4" %>
|
||||
<% end %>
|
||||
<%= render ButtonComponent.new(
|
||||
variant: "icon",
|
||||
icon: "refresh-cw",
|
||||
href: sync_plaid_item_path(plaid_item),
|
||||
method: :post,
|
||||
disabled: plaid_item.syncing? || plaid_item.scheduled_for_deletion?
|
||||
) %>
|
||||
<% end %>
|
||||
|
||||
<%= contextual_menu do %>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue