- <%= content_tag :div, class: ["flex items-center gap-2"] do %>
+ <%= content_tag :div, class: ["flex items-center gap-3 lg:gap-4"] do %>
<% if recurring_transaction.merchant.present? %>
<% if recurring_transaction.merchant.logo_url.present? %>
<%= image_tag Setting.transform_brand_fetch_url(recurring_transaction.merchant.logo_url),
- class: "w-6 h-6 rounded-full",
+ class: "w-9 h-9 rounded-full",
loading: "lazy" %>
<% else %>
<%= render DS::FilledIcon.new(
variant: :text,
text: recurring_transaction.merchant.name,
- size: "sm",
+ size: "lg",
rounded: true
) %>
<% end %>
@@ -21,27 +21,28 @@
<%= render DS::FilledIcon.new(
variant: :text,
text: recurring_transaction.name,
- size: "sm",
+ size: "lg",
rounded: true
) %>
<% end %>
+
<% display_amount = recurring_transaction.manual? && recurring_transaction.expected_amount_avg.present? ? recurring_transaction.expected_amount_avg : recurring_transaction.amount %>
<%= content_tag :p, format_money(-Money.new(display_amount, recurring_transaction.currency)), class: ["font-medium", display_amount.negative? ? "text-success" : "text-subdued"] %>
diff --git a/app/views/transactions/_list.html.erb b/app/views/transactions/_list.html.erb
new file mode 100644
index 000000000..1b0589e2a
--- /dev/null
+++ b/app/views/transactions/_list.html.erb
@@ -0,0 +1,53 @@
+<%# locals: (transactions:, projected_recurring:, q:, pagy:) %>
+
"
+ data-bulk-select-plural-label-value="<%= t(".transactions") %>"
+ class="flex flex-col bg-container rounded-xl shadow-border-xs px-3 py-4 lg:p-4 relative group">
+
+ <%= form_with url: imports_path, method: :post, class: "hidden", data: { drag_and_drop_import_target: "form" } do |f| %>
+ <%= f.hidden_field "import[type]", value: "TransactionImport" %>
+ <%= f.file_field "import[csv_file]", class: "hidden", data: { drag_and_drop_import_target: "input" }, accept: ".csv" %>
+ <% end %>
+
+ <%= render "imports/drag_drop_overlay", title: t(".drag_drop_title"), subtitle: t(".drag_drop_subtitle") %>
+
+ <%= render "transactions/searches/search" %>
+
+
+ <%= render "transactions/selection_bar" %>
+
+
+ <% if @pagy.count > 0 || (@projected_recurring.any? && @q.blank?) %>
+
+ <% if @transactions.any? %>
+
+
+ <%= check_box_tag "selection_entry",
+ class: "checkbox checkbox--light hidden lg:block",
+ data: {
+ action: "bulk-select#togglePageSelection",
+ checkbox_toggle_target: "selectionEntry"
+ } %>
+
transaction
+
+
+
<%= t("transactions.form.category_label") %>
+
<%= t("transactions.show.amount") %>
+
+ <% end %>
+
+
+ <%= entries_by_date(@transactions.map(&:entry), totals: true) do |entries| %>
+ <%= render entries %>
+ <% end %>
+
+
+ <% else %>
+ <%= render "entries/empty" %>
+ <% end %>
+
+
+ <%= render "shared/pagination", pagy: @pagy %>
+
+
\ No newline at end of file
diff --git a/app/views/transactions/_upcoming.html.erb b/app/views/transactions/_upcoming.html.erb
new file mode 100644
index 000000000..894883ff7
--- /dev/null
+++ b/app/views/transactions/_upcoming.html.erb
@@ -0,0 +1,29 @@
+<% if @projected_recurring.any? %>
+
+
+
<%= t("transactions.list.transaction") %>
+
<%= t("transactions.search.filters.type") %>
+
<%= t("transactions.show.amount") %>
+
+
+ <% @projected_recurring.group_by(&:next_expected_date).sort.each do |date, transactions| %>
+
+
+
+ <%= tag.span I18n.l(date, format: :long) %>
+ ·
+ <%= tag.span transactions.size %>
+
+
+
+ <% transactions.each do |recurring_transaction| %>
+ <%= render "recurring_transactions/projected_transaction", recurring_transaction: recurring_transaction %>
+ <% end %>
+
+
+ <% end %>
+
+
+<% else %>
+ <%= render "recurring_transactions/empty" %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/transactions/index.html.erb b/app/views/transactions/index.html.erb
index 0cac7a7c8..671710c06 100644
--- a/app/views/transactions/index.html.erb
+++ b/app/views/transactions/index.html.erb
@@ -44,88 +44,26 @@
<%= render "summary", totals: @search.totals %>
+ <% if Current.family.recurring_transactions_disabled? %>
+ <%= render "transactions/list", transactions: @transactions, projected_recurring: @projected_recurring, q: params[:q], pagy: @pagy %>
+ <% else %>
+ <%= render DS::Tabs.new(active_tab: params[:tab].presence || "transactions") do |tabs| %>
+ <% tabs.with_nav(classes: "max-w-fit") do |nav| %>
+ <% nav.with_btn(id: "transactions", label: t("transactions.show.tab_transactions"), classes: "px-6") %>
+ <% nav.with_btn(id: "upcoming", label: t("transactions.show.tab_upcoming"), classes: "px-6") %>
+ <% end %>
-
"
- data-bulk-select-plural-label-value="<%= t(".transactions") %>"
- class="flex flex-col bg-container rounded-xl shadow-border-xs px-3 py-4 lg:p-4 relative group">
-
- <%= form_with url: imports_path, method: :post, class: "hidden", data: { drag_and_drop_import_target: "form" } do |f| %>
- <%= f.hidden_field "import[type]", value: "TransactionImport" %>
- <%= f.file_field "import[csv_file]", class: "hidden", data: { drag_and_drop_import_target: "input" }, accept: ".csv" %>
- <% end %>
-
- <%= render "imports/drag_drop_overlay", title: "Drop CSV to import", subtitle: "Upload transactions directly" %>
-
- <%= render "transactions/searches/search" %>
-
-
- <%= render "transactions/selection_bar" %>
-
-
- <% if @pagy.count > 0 || (@projected_recurring.any? && @q.blank?) %>
-
- <% if @transactions.any? %>
-
-
- <%= check_box_tag "selection_entry",
- class: "checkbox checkbox--light hidden lg:block",
- data: {
- action: "bulk-select#togglePageSelection",
- checkbox_toggle_target: "selectionEntry"
- } %>
-
transaction
-
-
-
category
-
amount
-
- <% end %>
-
-
- <% if @projected_recurring.any? && @q.blank? %>
-
">
-
- "
- aria-expanded="<%= !Current.user.transactions_section_collapsed?("upcoming_recurring") %>">
- <%= icon("chevron-down", size: "sm", class: "transition-transform", data: { transactions_section_target: "chevron" }) %>
-
-
<%= t("recurring_transactions.upcoming") %>
-
-
- <% @projected_recurring.group_by(&:next_expected_date).sort.each do |date, transactions| %>
-
-
<%= l(date, format: :long) %>
- <% transactions.each do |recurring_transaction| %>
- <%= render "recurring_transactions/projected_transaction", recurring_transaction: recurring_transaction %>
- <% end %>
-
- <% end %>
-
-
- <% end %>
-
- <%= entries_by_date(@transactions.map(&:entry), totals: true) do |entries| %>
- <%= render entries %>
- <% end %>
+ <% tabs.with_panel(tab_id: "transactions") do %>
+
+ <%= render "transactions/list", transactions: @transactions, projected_recurring: @projected_recurring, q: params[:q], pagy: @pagy %>
-
- <% else %>
- <%= render "entries/empty" %>
- <% end %>
+ <% end %>
-
- <%= render "shared/pagination", pagy: @pagy %>
-
-
+ <% tabs.with_panel(tab_id: "upcoming") do %>
+
+ <%= render "transactions/upcoming" %>
+
+ <% end %>
+ <% end %>
+ <% end %>
diff --git a/config/locales/views/recurring_transactions/en.yml b/config/locales/views/recurring_transactions/en.yml
index 34749bc71..504d321d9 100644
--- a/config/locales/views/recurring_transactions/en.yml
+++ b/config/locales/views/recurring_transactions/en.yml
@@ -5,7 +5,10 @@ en:
upcoming: Upcoming Recurring Transactions
projected: Projected
recurring: Recurring
- expected_on: Expected on %{date}
+ expected_today: "Expected today"
+ expected_in:
+ one: "Expected in %{count} day"
+ other: "Expected in %{count} days"
day_of_month: Day %{day} of month
identify_patterns: Identify Patterns
cleanup_stale: Clean Up Stale
diff --git a/config/locales/views/transactions/en.yml b/config/locales/views/transactions/en.yml
index 00078d609..1dfa2704f 100644
--- a/config/locales/views/transactions/en.yml
+++ b/config/locales/views/transactions/en.yml
@@ -49,6 +49,8 @@ en:
overview: Overview
settings: Settings
tags_label: Tags
+ tab_transactions: Transactions
+ tab_upcoming: Upcoming
uncategorized: "(uncategorized)"
activity_labels:
buy: Buy
@@ -95,6 +97,11 @@ en:
transaction: transaction
transactions: transactions
import: Import
+ list:
+ drag_drop_title: Drop CSV to import
+ drag_drop_subtitle: Upload transactions directly
+ transaction: transaction
+ transactions: transactions
toggle_recurring_section: Toggle upcoming recurring transactions
search:
filters: