Skip to content
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
29 changes: 29 additions & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,35 @@ hr {
.embassy-appointment-card--stamping { border-top-color: #2672B5; }
.embassy-appointment-card--pending { border-top-color: #C41C1C; border-top-style: dashed; }
.embassy-appointment-card--expired { border-top-color: #7a8189; border-top-style: dashed; opacity: 0.9; }
.embassy-appointment-card--ready {
border-top-color: #16A34A;
background-color: #F0FDF4;
box-shadow: 0 0 0 2px #BBF7D0 inset;
}

.embassy-ready-badge,
.embassy-processing-badge {
display: inline-block;
color: #fff;
font-size: 0.6875rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
margin-right: 0.5rem;
vertical-align: middle;
}

.embassy-ready-badge { background: #16A34A; }
.embassy-processing-badge { background: #CA8A04; }

.btn-green {
background: #16A34A;
color: #fff;
border-color: #15803D;
}
.btn-green:hover { background: #15803D; }

/* Notary callout ------------------------------------------------------- */

Expand Down
14 changes: 14 additions & 0 deletions app/controllers/admin/embassy_applications_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ def unmark_received
notice: "Moved #{application.serial} back to the active queue."
end

def mark_ready
application = EmbassyApplication.find_by!(serial: params[:id])
application.update!(ready_at: Time.current)
redirect_back fallback_location: admin_embassy_applications_path,
notice: "Marked #{application.serial} as ready for pickup."
end

def unmark_ready
application = EmbassyApplication.find_by!(serial: params[:id])
application.update!(ready_at: nil)
redirect_back fallback_location: admin_embassy_applications_path,
notice: "Cleared ready status for #{application.serial}."
end

def destroy
application = EmbassyApplication.find_by!(serial: params[:id])
booking = application.embassy_booking
Expand Down
1 change: 1 addition & 0 deletions app/views/admin/embassy_applications/delivered.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<% content_for :title, "Delivered Passports — Embassy Admin" %>
<% content_for :container_width, "max-w-7xl" %>

<div class="flex items-center justify-between mb-6 gap-3 flex-wrap">
<div>
Expand Down
22 changes: 22 additions & 0 deletions app/views/admin/embassy_applications/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<% content_for :title, "Submitted Applications — Embassy Admin" %>
<% content_for :container_width, "max-w-7xl" %>

<div class="flex items-center justify-between mb-6 gap-3 flex-wrap">
<div>
Expand Down Expand Up @@ -43,6 +44,7 @@
<th><%= sort_link("Appointment", "appointment") %></th>
<th><%= sort_link("Submitted", "submitted") %></th>
<th>Pickup</th>
<th>Status</th>
<th></th>
</tr>
</thead>
Expand Down Expand Up @@ -71,9 +73,29 @@
<span class="text-muted">—</span>
<% end %>
</td>
<td>
<% if application.ready_at.present? %>
<span class="embassy-ready-badge">Ready</span>
<% else %>
<span class="embassy-processing-badge">Processing</span>
<% end %>
</td>
<td class="text-right whitespace-nowrap">
<%= link_to "View", admin_embassy_application_path(application),
class: "text-blue underline mr-3" %>
<% if application.ready_at.present? %>
<%= button_to "Unmark Ready",
unmark_ready_admin_embassy_application_path(application),
method: :patch,
class: "btn btn-ghost mr-2",
form: { class: "inline-block" } %>
<% else %>
<%= button_to "Mark Ready",
mark_ready_admin_embassy_application_path(application),
method: :patch,
class: "btn btn-green mr-2",
form: { class: "inline-block" } %>
<% end %>
<%= button_to "Mark Received",
mark_received_admin_embassy_application_path(application),
method: :patch,
Expand Down
21 changes: 19 additions & 2 deletions app/views/plan/_plan_item.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
if booking.nil? then "stamping"
elsif booking.passport_pickup? then "pickup"
elsif booking.stamping? then "stamping"
elsif application&.ready_at.present? then "ready"
elsif application&.submitted? then "submitted"
else "pending"
end
Expand Down Expand Up @@ -61,7 +62,23 @@

<% when "submitted" %>
<p class="plan-item__embassy-note">
Application filed · Serial <span class="mono"><%= application.serial %></span>
<span class="embassy-processing-badge">Processing</span>
Your application is being processed by the Embassy. Check this page for updates &mdash; we'll let you know once your passport is ready.
Serial <span class="mono"><%= application.serial %></span>
</p>
<% if application.notary_profile.present? %>
<%= render "embassy_applications/notary_callout", notary: application.notary_profile %>
<% end %>
<%= link_to "View / Download PDF",
embassy_application_path(application),
class: "btn btn-navy",
data: { turbo_frame: "_top" } %>

<% when "ready" %>
<p class="plan-item__embassy-note">
<span class="embassy-ready-badge">Ready</span>
Your passport is finished. Please present your application and notarization paperwork at the side table in the auditorium.
Serial <span class="mono"><%= application.serial %></span>
</p>
<% if application.notary_profile.present? %>
<%= render "embassy_applications/notary_callout", notary: application.notary_profile %>
Expand All @@ -81,7 +98,7 @@
</div>
</div>

<% unless %w[pickup submitted].include?(state) %>
<% unless %w[pickup submitted ready].include?(state) %>
<%= button_to "×",
plan_item_path(plan_item),
method: :delete,
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
member do
patch :mark_received
patch :unmark_received
patch :mark_ready
patch :unmark_ready
post :schedule_pickup
end
collection do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddReadyAtToEmbassyApplications < ActiveRecord::Migration[8.1]
def change
add_column :embassy_applications, :ready_at, :datetime
end
end
3 changes: 2 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions test/controllers/admin/embassy_applications_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,27 @@ def create_application_for(user, schedule_item)
end
assert_response :not_found
end

test "mark_ready stamps ready_at on the application" do
sign_in_as users(:jeremy)
assert_nil @application.ready_at
patch mark_ready_admin_embassy_application_path(@application.serial)
assert_not_nil @application.reload.ready_at
assert_match(/ready for pickup/, flash[:notice])
end

test "unmark_ready clears ready_at" do
@application.update!(ready_at: Time.current)
sign_in_as users(:jeremy)
patch unmark_ready_admin_embassy_application_path(@application.serial)
assert_nil @application.reload.ready_at
assert_match(/Cleared ready status/, flash[:notice])
end

test "non-admins cannot mark ready" do
sign_in_as users(:attendee_one)
patch mark_ready_admin_embassy_application_path(@application.serial)
assert_response :not_found
assert_nil @application.reload.ready_at
end
end
54 changes: 54 additions & 0 deletions test/integration/plan_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,60 @@ class PlanTest < ActionDispatch::IntegrationTest
end
end

test "/plan shows yellow Processing badge on embassy card while application is submitted but not yet ready" do
alice = users(:attendee_one)
passport_block = ScheduleItem.create!(
day: "thu", time_label: "9:00 AM", sort_time: 900,
title: "Passport Block", kind: :embassy, is_public: true,
offers_new_passport: true, new_passport_capacity: 4
)
plan_item = alice.plan_items.create!(schedule_item: passport_block)
booking = EmbassyBooking.create!(
user: alice, schedule_item: passport_block, plan_item: plan_item,
mode: "new_passport", state: "confirmed"
)
application = EmbassyApplication.create!(
embassy_booking: booking, state: "submitted", submitted_at: Time.current,
drawn_question_ids: [], notary_profile_id: nil
)

sign_in_as alice
get plan_path

assert_match "embassy-processing-badge", response.body
assert_match "being processed", response.body
assert_match application.serial, response.body
assert_no_match "embassy-ready-badge", response.body
end

test "/plan shows green READY badge on embassy card once application.ready_at is set" do
alice = users(:attendee_one)
passport_block = ScheduleItem.create!(
day: "thu", time_label: "9:00 AM", sort_time: 900,
title: "Passport Block", kind: :embassy, is_public: true,
offers_new_passport: true, new_passport_capacity: 4
)
plan_item = alice.plan_items.create!(schedule_item: passport_block)
booking = EmbassyBooking.create!(
user: alice, schedule_item: passport_block, plan_item: plan_item,
mode: "new_passport", state: "confirmed"
)
application = EmbassyApplication.create!(
embassy_booking: booking, state: "submitted", submitted_at: Time.current,
drawn_question_ids: [], notary_profile_id: nil,
ready_at: Time.current
)

sign_in_as alice
get plan_path

assert_match "embassy-appointment-card--ready", response.body
assert_match "embassy-ready-badge", response.body
assert_match application.serial, response.body
assert_no_match(/aria-label="Cancel appointment"/, response.body,
"cancel button is hidden once the embassy says ready")
end

test "/plan shows activity attendees, contact form for self, and contacts of co-RSVPers" do
alice = users(:attendee_one)
vic = users(:volunteer_one)
Expand Down
Loading