add no-JS fallback for contact page order tracking form
Some checks failed
deploy / deploy (push) Has been cancelled

Both order tracking forms now have action="/contact/lookup" so they
POST to a new OrderLookupController.lookup action when JS is off.
The controller mirrors the LiveView handler: checks for paid orders,
sends the verification email, and redirects with a flash message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-24 23:10:15 +00:00
parent 6ee8a31716
commit 6289c678f7
4 changed files with 80 additions and 2 deletions

View File

@ -167,7 +167,8 @@ defmodule BerrypodWeb.ShopComponents.Content do
<p class="card-text card-text--spaced"> <p class="card-text card-text--spaced">
No orders found for that address. Make sure you use the same email you checked out with. No orders found for that address. Make sure you use the same email you checked out with.
</p> </p>
<form phx-submit="lookup_orders" class="card-inline-form"> <form action="/contact/lookup" method="post" phx-submit="lookup_orders" class="card-inline-form">
<input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
<.shop_input <.shop_input
type="email" type="email"
name="email" name="email"
@ -188,7 +189,8 @@ defmodule BerrypodWeb.ShopComponents.Content do
<p class="card-text card-text--spaced"> <p class="card-text card-text--spaced">
Enter the email address you used at checkout and we'll send you a link. Enter the email address you used at checkout and we'll send you a link.
</p> </p>
<form phx-submit="lookup_orders" class="card-inline-form"> <form action="/contact/lookup" method="post" phx-submit="lookup_orders" class="card-inline-form">
<input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
<.shop_input <.shop_input
type="email" type="email"
name="email" name="email"

View File

@ -1,9 +1,45 @@
defmodule BerrypodWeb.OrderLookupController do defmodule BerrypodWeb.OrderLookupController do
use BerrypodWeb, :controller use BerrypodWeb, :controller
alias Berrypod.Orders
alias Berrypod.Orders.OrderNotifier
@salt "order_lookup" @salt "order_lookup"
@max_age 3_600 @max_age 3_600
@doc """
Looks up orders by email and sends a verification link (no-JS fallback).
"""
def lookup(conn, %{"email" => email}) when is_binary(email) and email != "" do
orders = Orders.list_orders_by_email(email)
if orders == [] do
conn
|> put_flash(
:error,
"No orders found for that address. Make sure you use the same email you checked out with."
)
|> redirect(to: ~p"/contact")
else
token = generate_token(email)
link = BerrypodWeb.Endpoint.url() <> ~p"/orders/verify/#{token}"
OrderNotifier.deliver_order_lookup(email, link)
conn
|> put_flash(
:info,
"We've sent a link to your email address. It'll expire after an hour."
)
|> redirect(to: ~p"/contact")
end
end
def lookup(conn, _params) do
conn
|> put_flash(:error, "Please enter your email address.")
|> redirect(to: ~p"/contact")
end
def verify(conn, %{"token" => token}) do def verify(conn, %{"token" => token}) do
case Phoenix.Token.verify(BerrypodWeb.Endpoint, @salt, token, max_age: @max_age) do case Phoenix.Token.verify(BerrypodWeb.Endpoint, @salt, token, max_age: @max_age) do
{:ok, email} -> {:ok, email} ->

View File

@ -90,6 +90,9 @@ defmodule BerrypodWeb.Router do
# Checkout (POST — creates Stripe session and redirects) # Checkout (POST — creates Stripe session and redirects)
post "/checkout", CheckoutController, :create post "/checkout", CheckoutController, :create
# Order lookup (no-JS fallback for contact page form)
post "/contact/lookup", OrderLookupController, :lookup
# Cart form actions (no-JS fallbacks for LiveView cart events) # Cart form actions (no-JS fallbacks for LiveView cart events)
post "/cart/add", CartController, :add post "/cart/add", CartController, :add
post "/cart/remove", CartController, :remove post "/cart/remove", CartController, :remove

View File

@ -0,0 +1,37 @@
defmodule BerrypodWeb.OrderLookupControllerTest do
use BerrypodWeb.ConnCase, async: false
import Berrypod.AccountsFixtures
import Berrypod.OrdersFixtures
setup do
user_fixture()
{:ok, _} = Berrypod.Settings.set_site_live(true)
:ok
end
describe "POST /contact/lookup" do
test "sends lookup email and redirects when orders exist", %{conn: conn} do
order_fixture(%{customer_email: "buyer@test.com", payment_status: "paid"})
conn = post(conn, ~p"/contact/lookup", %{"email" => "buyer@test.com"})
assert redirected_to(conn) == "/contact"
assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "sent a link"
end
test "shows error when no orders found", %{conn: conn} do
conn = post(conn, ~p"/contact/lookup", %{"email" => "nobody@test.com"})
assert redirected_to(conn) == "/contact"
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "No orders found"
end
test "shows error when email is missing", %{conn: conn} do
conn = post(conn, ~p"/contact/lookup", %{})
assert redirected_to(conn) == "/contact"
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "enter your email"
end
end
end