Skip to content

Commit cbe69e0

Browse files
committed
Highlight and scroll to updated loans.
1 parent db7db07 commit cbe69e0

16 files changed

+161
-59
lines changed

app/controllers/admin/loans_controller.rb

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Admin
22
class LoansController < BaseController
3+
include ActionView::RecordIdentifier
4+
35
def index
46
scope = if params[:member_id]
57
Member.find(params[:member_id]).loans
@@ -16,7 +18,7 @@ def create
1618
@loan = Loan.lend(@item, to: @member)
1719

1820
if @loan.save
19-
redirect_to admin_member_path(@loan.member, anchor: "current-loans") # , success: "Loan was successfully created."
21+
redirect_to admin_member_path(@loan.member, anchor: dom_id(@loan))
2022
else
2123
flash[:checkout_error] = @loan.errors.full_messages_for(:item_id).join
2224
redirect_to admin_member_path(@loan.member, anchor: "checkout")
@@ -35,7 +37,7 @@ def update
3537
Adjustment.create!(member_id: @loan.member_id, adjustable: @loan, amount: amount * -1, kind: "fine")
3638
end
3739
end
38-
redirect_to admin_member_path(@loan.member, anchor: "current-loans") # , success: "Loan was successfully updated."
40+
redirect_to admin_member_path(@loan.member, anchor: dom_id(@loan))
3941
else
4042
flash[:checkout_error] = @loan.errors.full_messages_for(:item_id).join
4143
redirect_to admin_member_path(@loan.member, anchor: "checkout")
@@ -46,8 +48,7 @@ def destroy
4648
@loan = Loan.find(params[:id])
4749

4850
if !@loan.renewal? && @loan.destroy
49-
message = "The loan was removed."
50-
redirect_to admin_member_path(@loan.member, anchor: "current-loans"), success: message
51+
redirect_to admin_member_path(@loan.member)
5152
else
5253
redirect_to admin_member_path(@loan.member, anchor: "checkout"), error: "Loan could not be destroyed!"
5354
end

app/controllers/admin/members_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def show
1515
@new_item_numbers = []
1616
@new_loans = {}
1717

18+
@returned_loan_summaries = @member.loan_summaries.returned_since(Time.current.beginning_of_day).includes(:latest_loan, item: :borrow_policy).by_end_date
1819
@active_loan_summaries = @member.loan_summaries.checked_out.includes(:latest_loan, item: :borrow_policy).by_due_date
1920

2021
@check_out = CheckOut.new

app/controllers/admin/renewals_controller.rb

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
module Admin
22
class RenewalsController < BaseController
3+
include ActionView::RecordIdentifier
4+
35
def create
46
@loan = Loan.find(params[:loan_id])
5-
@loan.renew!
7+
@renewal = @loan.renew!
68

7-
redirect_to admin_member_url(@loan.member_id, anchor: "current-loans")
9+
redirect_to admin_member_url(@loan.member_id, anchor: dom_id(@renewal))
810
end
911

1012
def destroy
1113
@loan = Loan.find(params[:id])
1214

1315
if @loan.renewal?
14-
@loan.undo_renewal!
15-
redirect_to admin_member_path(@loan.member, anchor: "current-loans")
16+
@previous_loan = @loan.undo_renewal!
17+
redirect_to admin_member_path(@loan.member, anchor: dom_id(@previous_loan))
1618
else
1719
redirect_to admin_member_path(@loan.member, anchor: "current-loans"), error: "Renewal could not be destroyed!"
1820
end

app/helpers/loans_helper.rb

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
module LoansHelper
22
def undo_button(loan)
3-
name, path = if loan.renewal?
4-
["renewal", admin_renewal_path(loan)]
3+
name, method, path, params = if loan.ended?
4+
["return", :patch, admin_loan_path(loan), {loan: {ended_at: nil}}]
5+
elsif loan.renewal?
6+
["renewal", :delete, admin_renewal_path(loan)]
57
else
6-
["loan", admin_loan_path(loan)]
8+
["loan", :delete, admin_loan_path(loan)]
79
end
8-
button_to path, method: :delete, class: "btn btn-sm", remote: true do
10+
button_to path, method: method, class: "btn btn-sm", remote: true, params: params do
911
feather_icon("x") + "Undo #{name}"
1012
end
1113
end

app/javascript/packs/application.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,17 @@ document.addEventListener("turbolinks:load", function() {
2222
height: 20,
2323
class: "feather-icon",
2424
});
25-
})
25+
})
26+
27+
import scrollIntoView from 'smooth-scroll-into-view-if-needed';
28+
29+
Turbolinks.ScrollManager.prototype.scrollToElement = function(element) {
30+
let classes = element.classList;
31+
if (classes.contains("highlightable")) {
32+
classes.add("highlight");
33+
}
34+
scrollIntoView(element, {
35+
behavior: 'smooth',
36+
scrollMode: 'if-needed',
37+
});
38+
}

app/javascript/stylesheets/application.scss

+3-3
Original file line numberDiff line numberDiff line change
@@ -489,12 +489,12 @@ form.membership-amount {
489489
padding-top: 0.4rem;
490490
}
491491

492-
.brand-new {
493-
animation: brand-new-fade-out 1.5s;
492+
.highlight {
493+
animation: highlight-fade-out 1.5s;
494494
}
495495
}
496496

497-
@keyframes brand-new-fade-out {
497+
@keyframes highlight-fade-out {
498498
from {
499499
background-color: antiquewhite;
500500
}

app/models/loan.rb

+5-3
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@ def renew!(now = Time.current)
8686
def undo_renewal!
8787
transaction do
8888
destroy!
89-
if renewal_count > 1
90-
initial_loan.renewals.order(created_at: :desc).where.not(id: id).first.update!(ended_at: nil)
89+
target = if renewal_count > 1
90+
initial_loan.renewals.order(created_at: :desc).where.not(id: id).first
9191
else
92-
initial_loan.update!(ended_at: nil)
92+
initial_loan
9393
end
94+
target.update!(ended_at: nil)
95+
target
9496
end
9597
end
9698

app/models/loan_summary.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class LoanSummary < ApplicationRecord
1616
scope :overdue, -> { overdue_as_of(Time.current) }
1717
scope :overdue_as_of, ->(date) { checked_out.where "due_at < ?", date }
1818
scope :returned, -> { where.not(ended_at: nil) }
19-
scope :recently_returned, -> { where.not(ended_at: nil).where("loan_summaries.ended_at >= ?", Time.current - 30.days) }
19+
scope :returned_since, ->(date) { where("loan_summaries.ended_at >= ?", date) }
2020

2121
scope :by_end_date, -> { order(ended_at: :asc) }
2222
scope :by_due_date, -> { order(due_at: :asc) }

app/views/admin/items/index.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<strong><%= pluralize @pagy.count, "item" %></strong> tagged with
1313
<span class="chip">
1414
<%= @tag.name %>
15-
<%= link_to "", items_path, :class => "btn btn-clear", "aria-label" => "Clear filter", :role => "button", title: "Clear filter" %>
15+
<%= link_to "", {tag: nil}, :class => "btn btn-clear", "aria-label" => "Clear filter", :role => "button", title: "Clear filter" %>
1616
</span>,
1717
<% else %>
1818
all <strong><%= pluralize @pagy.count, "item" %></strong>,

app/views/admin/members/_profile.html.erb

+8-4
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@
1313
<li><%= feather_icon "user" %> <%= @member.full_name %></li>
1414
<li><%= feather_icon "mail" %> <%= @member.email %></li>
1515
<li><%= feather_icon "smartphone" %> <%= format_phone_number @member.phone_number %></li>
16-
<li>
17-
<%= feather_icon "credit-card" %>
18-
<%= link_to @member.account_balance.format, admin_member_adjustments_path(@member) %>
19-
</li>
16+
</ul>
17+
18+
<ul class="member-stats">
19+
<li><%= feather_icon "tool" %> <%= pluralize(@member.loans.checked_out.count, "item") %> checked out</li>
2020
</ul>
2121

2222
<ul class="member-stats">
2323
<% if @member.status_verified? %>
2424
<li><%= feather_icon "user-check" %> Info verified</li>
2525
<% end %>
26+
<li>
27+
<%= feather_icon "credit-card" %>
28+
<%= link_to @member.account_balance.format, admin_member_adjustments_path(@member) %>
29+
</li>
2630
<% if @member.active_membership %>
2731
<li>
2832
<%= feather_icon "key" %>

app/views/admin/members/show.html.erb

+40-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,45 @@
66
</div>
77
<% end %>
88

9-
<% if @active_loan_summaries.any? %>
9+
<% if @returned_loan_summaries.any? %>
10+
<div id="returned-loans" class="member-active-loans">
11+
<div class="columns">
12+
<div class="column">
13+
<p class="h5 due-date">Returned <strong>Today</strong></p>
14+
</div>
15+
</div>
16+
<% @returned_loan_summaries.each do |summary| %>
17+
<div id="<%= dom_id summary.latest_loan %>" class="columns mt-2 mb-2 highlightable">
18+
<div class="column col-sm-6 col-4">
19+
<%= tag.div class: "item-image" do %>
20+
<% if summary.item.image.attached? %>
21+
<%= link_to admin_item_path(summary.item) do %>
22+
<%= image_tag url_for(rotated_variant(summary.item.image, resize_to_limit: [160, 112])), class: "p-right" %>
23+
<% end %>
24+
<% else %>
25+
<div class="image-placeholder"></div>
26+
<% end %>
27+
<% end %>
28+
</div>
29+
<div class="column col-sm-6 col-4">
30+
<p><%= full_item_number(summary.item) %></p>
31+
<p><%= link_to summary.item.name, admin_item_path(summary.item) %></p>
32+
<% if summary.renewed? %>
33+
<p>
34+
<%= tag.span class:"tooltip tooltip-bottom more-info", data: {tooltip:"Initial check out #{checked_out_date(summary.created_at)}"} do %>Renewed <%= pluralize(summary.renewal_count, "time") %><% end %>
35+
</p>
36+
<% end %>
37+
</div>
38+
<div class="column col-sm-12 col-4 text-right">
39+
<%= undo_button summary.latest_loan %>
40+
</div>
41+
</div>
42+
<% end %>
43+
<div class="divider"></div>
44+
</div>
45+
<% end %>
1046

47+
<% if @active_loan_summaries.any? %>
1148
<div id="current-loans" class="member-active-loans">
1249
<% @active_loan_summaries.group_by(&:due_at).each do |due_at, summaries| %>
1350
<div class="columns">
@@ -18,12 +55,12 @@
1855
</div>
1956
</div>
2057
<% summaries.sort_by { |s| s.latest_loan.updated_at }.each do |summary| %>
21-
<div class="columns mt-2 mb-2<%= " brand-new" if summary.latest_loan.updated_at > 2.second.ago %>">
58+
<div id="<%= dom_id summary.latest_loan %>" class="columns mt-2 mb-2 highlightable">
2259
<div class="column col-sm-6 col-4">
2360
<%= tag.div class: "item-image" do %>
2461
<% if summary.item.image.attached? %>
2562
<%= link_to admin_item_path(summary.item) do %>
26-
<%= image_tag url_for(rotated_variant(summary.item.image, resize_to_limit: [200, 140])), class: "p-right" %>
63+
<%= image_tag url_for(rotated_variant(summary.item.image, resize_to_limit: [160, 112])), class: "p-right" %>
2764
<% end %>
2865
<% else %>
2966
<div class="image-placeholder"></div>

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"jquery": "^3.4.1",
1313
"mjml": "^4.4.0",
1414
"selectize": "^0.12.6",
15+
"smooth-scroll-into-view-if-needed": "^1.1.27",
1516
"spectre.css": "^0.5.8",
1617
"stimulus": "^1.1.1",
1718
"trix": "^1.0.0",

test/controllers/admin/loans_controller_test.rb

+7-7
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,33 @@ class LoansControllerTest < ActionDispatch::IntegrationTest
2020
post admin_loans_url, params: {loan: {item_id: @item.id, member_id: member.id}}
2121
end
2222

23-
assert_redirected_to admin_member_url(member, anchor: "current-loans")
23+
assert_redirected_to admin_member_url(member, anchor: "loan_#{Loan.last.id}")
2424
end
2525

26-
test "should update loan" do
26+
test "should return item by updating loan" do
2727
@loan = create(:loan, item: @item)
2828
patch admin_loan_url(@loan), params: {loan: {ended: "1"}}
29-
assert_redirected_to admin_member_url(@loan.member, anchor: "current-loans")
29+
assert_redirected_to admin_member_url(@loan.member, anchor: "loan_#{@loan.id}")
3030

3131
@loan.reload
3232
refute flash[:checkout_error]
3333
assert @loan.ended_at.present?
3434
end
3535

36-
test "should update loan for an overdue item" do
36+
test "should return item by updating loan for an overdue item" do
3737
@loan = create(:loan, item: @item, due_at: 8.days.ago)
3838
patch admin_loan_url(@loan), params: {loan: {ended: "1"}}
39-
assert_redirected_to admin_member_url(@loan.member, anchor: "current-loans")
39+
assert_redirected_to admin_member_url(@loan.member, anchor: "loan_#{@loan.id}")
4040

4141
@loan.reload
4242
refute flash[:checkout_error]
4343
assert @loan.ended_at.present?
4444
end
4545

46-
test "should update loan and mark as not ended" do
46+
test "should undo a return by marking as not ended" do
4747
ended_loan = create(:ended_loan)
4848
patch admin_loan_url(ended_loan), params: {loan: {ended: "0"}}
49-
assert_redirected_to admin_member_url(ended_loan.member, anchor: "current-loans")
49+
assert_redirected_to admin_member_url(ended_loan.member, anchor: "loan_#{ended_loan.id}")
5050

5151
ended_loan.reload
5252
assert ended_loan.ended_at.nil?

test/controllers/admin/renewals_controller_test.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class RenewalsControllerTest < ActionDispatch::IntegrationTest
1515
post admin_renewals_url(loan_id: @loan)
1616
end
1717

18-
assert_redirected_to admin_member_url(@loan.member, anchor: "current-loans")
18+
assert_redirected_to admin_member_url(@loan.member, anchor: "loan_#{Loan.last.id}")
1919

2020
@loan.reload
2121

@@ -39,7 +39,7 @@ class RenewalsControllerTest < ActionDispatch::IntegrationTest
3939
delete admin_renewal_url(@renewal)
4040
end
4141

42-
assert_redirected_to admin_member_url(@loan.member, anchor: "current-loans")
42+
assert_redirected_to admin_member_url(@loan.member, anchor: "loan_#{@loan.id}")
4343

4444
@loan.reload
4545

0 commit comments

Comments
 (0)