Skip to content
This repository was archived by the owner on Jul 27, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions app/controllers/account/entries_controller.rb

This file was deleted.

8 changes: 8 additions & 0 deletions app/controllers/concerns/accountable_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module AccountableResource
extend ActiveSupport::Concern

included do
include ScrollFocusable

layout :with_sidebar
before_action :set_account, only: [ :show, :edit, :update, :destroy ]
before_action :set_link_token, only: :new
Expand All @@ -22,6 +24,12 @@ def new
end

def show
@q = params.fetch(:q, {}).permit(:search)
entries = @account.entries.search(@q).reverse_chronological

set_focused_record(entries, params[:focused_record_id])

@pagy, @entries = pagy(entries, limit: params[:per_page] || "10", params: ->(params) { params.except(:focused_record_id) })
end

def edit
Expand Down
21 changes: 21 additions & 0 deletions app/controllers/concerns/scroll_focusable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module ScrollFocusable
extend ActiveSupport::Concern

def set_focused_record(record_scope, record_id, default_per_page: 10)
return unless record_id.present?

@focused_record = record_scope.find_by(id: record_id)

record_index = record_scope.pluck(:id).index(record_id)

return unless record_index

page_of_focused_record = (record_index / (params[:per_page]&.to_i || default_per_page)) + 1

if params[:page]&.to_i != page_of_focused_record
(
redirect_to(url_for(page: page_of_focused_record, focused_record_id: record_id))
)
end
end
end
78 changes: 76 additions & 2 deletions app/controllers/transactions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
class TransactionsController < ApplicationController
include ScrollFocusable

layout :with_sidebar

before_action :store_params!, only: :index

def index
@q = search_params
search_query = Current.family.transactions.search(@q).reverse_chronological
@pagy, @transaction_entries = pagy(search_query, limit: params[:per_page] || "50")

set_focused_record(search_query, params[:focused_record_id], default_per_page: 50)

@pagy, @transaction_entries = pagy(
search_query,
limit: params[:per_page].presence || default_params[:per_page],
params: ->(params) { params.except(:focused_record_id) }
)

totals_query = search_query.incomes_and_expenses
family_currency = Current.family.currency
Expand All @@ -18,13 +29,76 @@ def index
}
end

def clear_filter
updated_params = stored_params.deep_dup

q_params = updated_params["q"] || {}

param_key = params[:param_key]
param_value = params[:param_value]

if q_params[param_key].is_a?(Array)
q_params[param_key].delete(param_value)
q_params.delete(param_key) if q_params[param_key].empty?
else
q_params.delete(param_key)
end

updated_params["q"] = q_params.presence
Current.session.update!(prev_transaction_page_params: updated_params)

redirect_to transactions_path(updated_params)
end

private
def search_params
params.fetch(:q, {})
cleaned_params = params.fetch(:q, {})
.permit(
:start_date, :end_date, :search, :amount,
:amount_operator, accounts: [], account_ids: [],
categories: [], merchants: [], types: [], tags: []
)
.to_h
.compact_blank

cleaned_params.delete(:amount_operator) unless cleaned_params[:amount].present?

cleaned_params
end

def store_params!
if should_restore_params?
params_to_restore = {}

params_to_restore[:q] = stored_params["q"].presence || default_params[:q]
params_to_restore[:page] = stored_params["page"].presence || default_params[:page]
params_to_restore[:per_page] = stored_params["per_page"].presence || default_params[:per_page]

redirect_to transactions_path(params_to_restore)
else
Current.session.update!(
prev_transaction_page_params: {
q: search_params,
page: params[:page],
per_page: params[:per_page]
}
)
end
end

def should_restore_params?
request.query_parameters.blank? && (stored_params["q"].present? || stored_params["page"].present? || stored_params["per_page"].present?)
end

def stored_params
Current.session.prev_transaction_page_params
end

def default_params
{
q: {},
page: 1,
per_page: 50
}
end
end
20 changes: 0 additions & 20 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,24 +176,4 @@ def show_super_admin_bar?

cookies[:admin] == "true"
end

def custom_pagy_url_for(pagy, page, current_path: nil)
if current_path.blank?
pagy_url_for(pagy, page)
else
uri = URI.parse(current_path)
params = URI.decode_www_form(uri.query || "").to_h

# Delete existing page param if it exists
params.delete("page")
# Add new page param unless it's page 1
params["page"] = page unless page == 1

if params.empty?
uri.path
else
"#{uri.path}?#{URI.encode_www_form(params)}"
end
end
end
end
17 changes: 0 additions & 17 deletions app/helpers/transactions_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,4 @@ def get_transaction_search_filter_partial_path(filter)
def get_default_transaction_search_filter
transaction_search_filters[0]
end

def transactions_path_without_param(param_key, param_value)
updated_params = request.query_parameters.deep_dup

q_params = updated_params[:q] || {}

current_value = q_params[param_key]
if current_value.is_a?(Array)
q_params[param_key] = current_value - [ param_value ]
else
q_params.delete(param_key)
end

updated_params[:q] = q_params

transactions_path(updated_params)
end
end
21 changes: 21 additions & 0 deletions app/javascript/controllers/focus_record_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="focus-record"
export default class extends Controller {
static values = {
id: String,
};

connect() {
const element = document.getElementById(this.idValue);

if (element) {
element.scrollIntoView({ behavior: "smooth" });

// Remove the focused_record_id parameter from URL
const url = new URL(window.location);
url.searchParams.delete("focused_record_id");
window.history.replaceState({}, "", url);
}
}
}
20 changes: 20 additions & 0 deletions app/javascript/controllers/selectable_link_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="selectable-link"
export default class extends Controller {
connect() {
this.element.addEventListener("change", this.handleChange.bind(this));
}

disconnect() {
this.element.removeEventListener("change", this.handleChange.bind(this));
}

handleChange(event) {
const paramName = this.element.name;
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set(paramName, event.target.value);

Turbo.visit(currentUrl.toString());
}
}
93 changes: 0 additions & 93 deletions app/views/account/entries/index.html.erb

This file was deleted.

4 changes: 2 additions & 2 deletions app/views/account/transactions/_transaction.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%# locals: (entry:, selectable: true, balance_trend: nil) %>
<% transaction, account = entry.account_transaction, entry.account %>

<div class="grid grid-cols-12 items-center text-gray-900 text-sm font-medium p-4">
<div class="grid grid-cols-12 items-center text-gray-900 text-sm font-medium p-4 <%= @focused_record == entry ? "border border-gray-900 rounded-lg" : "" %>">
<div class="pr-10 flex items-center gap-4 <%= balance_trend ? "col-span-6" : "col-span-8" %>">
<% if selectable %>
<%= check_box_tag dom_id(entry, "selection"),
Expand Down Expand Up @@ -45,7 +45,7 @@
<% if entry.account_transaction.transfer? %>
<%= render "transfers/account_links", transfer: entry.account_transaction.transfer, is_inflow: entry.account_transaction.transfer_as_inflow.present? %>
<% else %>
<%= link_to entry.account.name, account_path(entry.account, tab: "transactions"), data: { turbo_frame: "_top" }, class: "hover:underline" %>
<%= link_to entry.account.name, account_path(entry.account, tab: "transactions", focused_record_id: entry.id), data: { turbo_frame: "_top" }, class: "hover:underline" %>
<% end %>
</div>
</div>
Expand Down
Loading