Skip to content

Commit

Permalink
Migrate hold position editing to Turbo.
Browse files Browse the repository at this point in the history
  • Loading branch information
jim committed Nov 20, 2023
1 parent 0042586 commit cf34066
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
tbody tr {
.drag-handle {
cursor: grab;
width: 36px;
}
&.notified {
background: $gray-color-light;
Expand Down
19 changes: 19 additions & 0 deletions app/controllers/admin/items/hold_positions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Admin
module Items
class HoldPositionsController < BaseController
def update
@hold = @item.active_holds.find(params[:id])
@hold.insert_at(params[:position].to_i)

@holds = @item.active_holds.ordered_by_position.includes(:member)

respond_to do |format|
format.turbo_stream {
render turbo_stream: turbo_stream.replace("holds-list",
render_to_string(partial: "admin/items/holds/list", locals: {holds: @holds}))
}
end
end
end
end
end
21 changes: 0 additions & 21 deletions app/controllers/admin/items/holds/positions_controller.rb

This file was deleted.

15 changes: 4 additions & 11 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// import Rails from "@rails/ujs"
// Rails.start()

import "@hotwired/turbo-rails"

import * as ActiveStorage from "@rails/activestorage"
Expand All @@ -11,14 +8,10 @@ import "./controllers"
import "trix"
import "@rails/actiontext"

import feather from "feather-icons/dist/feather"
document.addEventListener("turbolinks:load", function() {
feather.replace({
width: 20,
height: 20,
class: "feather-icon",
});
})
import { setupFeatherIcons } from "./lib/feather"

document.documentElement.addEventListener("turbo:load", setupFeatherIcons);
// document.documentElement.addEventListener("turbo:frame-render", setupFeatherIcons);

// import scrollIntoView from 'smooth-scroll-into-view-if-needed';
//
Expand Down
60 changes: 0 additions & 60 deletions app/javascript/controllers/hold_order_controller.js

This file was deleted.

52 changes: 52 additions & 0 deletions app/javascript/controllers/hold_position_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Controller } from "@hotwired/stimulus"
import Sortable from "sortablejs"
import { setupFeatherIcons } from "../lib/feather"

export default class extends Controller {
static targets = [ "tbody" ]

connect() {
this.sortable = Sortable.create(this.tbodyTarget, {
animation: 150,
handle: ".drag-handle",
filter: ".notified",
onEnd: this.end.bind(this),
onMove: (event) => {
if (event.related.classList.contains('notified')) return false;
},
chosenClass: "sorting",
ghostClass: "ghost",
})

this.token = document.querySelector(
'meta[name="csrf-token"]'
).content;

setupFeatherIcons();
}

end(event) {
const id = event.item.dataset.holdId
const index = event.newIndex;
const previousItem = this.element.querySelector(`*[data-initial-index="${index}"]`);
const position = previousItem.dataset.position;

let url = this.data.get("url").replace(":id", id);

fetch(url, {
method: 'PUT',
headers: {
'X-CSRF-Token': this.token,
'Content-Type': 'application/json',
'Accept': "text/vnd.turbo-stream.html",
},
credentials: 'same-origin',
body: JSON.stringify({
position: position,
})
}).then(response => response.text())
.then(html => {
Turbo.renderStreamMessage(html);
});
}
}
4 changes: 2 additions & 2 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ application.register("email-settings-editor", EmailSettingsEditorController)
import FindToolController from "./find_tool_controller"
application.register("find-tool", FindToolController)

import HoldOrderController from "./hold_order_controller"
application.register("hold-order", HoldOrderController)
import HoldPositionController from "./hold_position_controller"
application.register("hold-position", HoldPositionController)

import ImageEditorController from "./image_editor_controller"
application.register("image-editor", ImageEditorController)
Expand Down
9 changes: 9 additions & 0 deletions app/javascript/lib/feather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import feather from "feather-icons/dist/feather"

export function setupFeatherIcons() {
feather.replace({
width: 20,
height: 20,
class: "feather-icon",
});
}
13 changes: 0 additions & 13 deletions app/views/admin/items/holds/_holds_rows.html.erb

This file was deleted.

28 changes: 28 additions & 0 deletions app/views/admin/items/holds/_list.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div id="holds-list">
<div data-controller="hold-position" data-hold-position-url="<%= admin_item_hold_position_path(@item, ":id") %>">
<table class="table item-holds-table">
<thead>
<th></th>
<th>#</th>
<th>Member</th>
<th>Reserved</th>
<th>Wait time</th>
<th>Expires on</th>
<th class="text-center">Notified?</th>
</thead>
<tbody data-hold-position-target="tbody">
<% @holds.ordered_by_position.each_with_index do |hold, index| %>
<tr data-initial-index="<%= index %>" data-position="<%= hold.position %>" data-hold-id="<%= hold.id %>" class="<%= "notified" if hold.started? %>">
<td class="drag-handle text-center" title="drag to reorder holds"><%= feather_icon("code") unless hold.started? %></td>
<td><%= index + 1 %></td>
<td><%= link_to preferred_or_default_name(hold.member), admin_member_holds_path(hold.member) %></td>
<td><%= date_with_time_title hold.created_at %></td>
<td><%= wait_time(hold) %></td>
<td><%= date_with_time_title(hold.expires_at) if hold.expires_at %></td>
<td class="text-center"><%= hold.started? ? "✔️" : "" %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
20 changes: 2 additions & 18 deletions app/views/admin/items/holds/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,21 @@
</div>

<% if params[:inactive].blank? %>
<div data-controller="hold-order" data-hold-order-url="<%= admin_item_holds_path(@item) %>/:id/position">
<table class="table item-holds-table">
<thead>
<th></th>
<th>#</th>
<th>Member</th>
<th>Reserved</th>
<th>Wait time</th>
<th>Expires on</th>
<th class="text-center">Notified?</th>
</thead>
<tbody data-hold-order-target="tbody">
<%= render partial: "admin/items/holds/holds_rows" %>
</tbody>
</table>
</div>
<%= render "list", locals: { holds: @holds } %>
<% else %>
<table class="table item-holds-table">
<thead>
<th>Member</th>
<th>Reserved</th>
<th>Picked up on</th>
</thead>
<tbody data-hold-order-target="tbody">
<tbody data-hold-position-target="tbody">
<% @holds.each do |hold| %>
<tr data-hold-id="<%= hold.id %>">
<td>
<%= link_to preferred_or_default_name(hold.member), admin_member_holds_path(hold.member) %>
</td>
<td><%= date_with_time_title hold.created_at %></td>
<td><%= date_with_time_title(hold.loan.created_at) if hold.loan %></td>
</tr>
<% end %>
</tbody>
Expand Down
7 changes: 2 additions & 5 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,8 @@
scope module: "items" do
resources :attachments
resource :history, only: :show
resources :holds, only: :index do
scope module: "holds" do
resource :position, only: :update
end
end
resources :holds, only: :index
resources :hold_positions, only: [:index, :update]
resources :notes
if ENV["FEATURE_MAINTENANCE_WORKFLOW"] == "on"
resources :tickets do
Expand Down
32 changes: 32 additions & 0 deletions test/controllers/admin/items/hold_positions_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require "test_helper"

module Admin
module Items
class HoldPositionsControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers

setup do
@user = create(:admin_user)
create(:verified_member, user: @user)

sign_in @user
end

test "updates positions of holds" do
item = create(:item)
10.times { create(:hold, item: item) }
holds = item.holds.ordered_by_position
hold_ids = holds.map(&:id)

patch admin_item_hold_position_path(item.id, hold_ids[7]), params: {position: holds[2].position}, as: :turbo_stream

assert_response :success

reordered_hold_ids = item.holds.ordered_by_position.map(&:id)
expected_hold_ids = hold_ids[0..1] + [hold_ids[7]] + hold_ids[2..6] + hold_ids[8..]

assert_equal expected_hold_ids, reordered_hold_ids
end
end
end
end
34 changes: 0 additions & 34 deletions test/controllers/admin/items/holds/positions_controller_test.rb

This file was deleted.

0 comments on commit cf34066

Please sign in to comment.