Device flow: single state resolver + shared terminal-state partial

The terminal states (expired / already-used / not-found) were duplicated as
markup in show and result, and #verify re-implemented the nil→expired→!pending
cascade that #show already had — a copy edit meant four touch points.

- device_code_state(dc) resolves a code to :not_found / :expired /
  :already_handled / :ok. Both #show and #verify branch on it, so the cascade
  lives in one place.
- _terminal_state partial renders the terminal heading/message/link once;
  result.html.erb now renders it instead of inlining the markup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7cwhwDJp3MJJDoNPVE6zq
This commit is contained in:
Dan Milne
2026-07-19 14:10:04 +10:00
co-authored by Claude Opus 4.8
parent e3f0bd4cab
commit 79a7524fda
4 changed files with 73 additions and 30 deletions
@@ -31,13 +31,7 @@
</p>
<% else %>
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">
<%= @state == :expired ? "Code expired" : (@state == :already_handled ? "Code already used" : "Code not found") %>
</h2>
<p class="mt-3 text-sm text-gray-600 dark:text-gray-400">
Start again from your tool to get a fresh code.
</p>
<%= link_to "Enter a different code", device_verification_path, class: "mt-6 inline-block text-sm font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400" %>
<%= render "terminal_state", state: @state %>
<% end %>
</div>
</div>