add no-JS fallback for cart country selector
All checks were successful
deploy / deploy (push) Successful in 59s
All checks were successful
deploy / deploy (push) Successful in 59s
The delivery country form now has action="/cart/country" with a noscript submit button. Without JS, changing the country and clicking Update POSTs to a new CartController.update_country action that saves the country to session and redirects back to /cart. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
79764c7766
commit
d0ea9d59f5
@ -403,7 +403,8 @@ defmodule BerrypodWeb.ShopComponents.Cart do
|
|||||||
<span class="delivery-line-label">
|
<span class="delivery-line-label">
|
||||||
Delivery to
|
Delivery to
|
||||||
<%= if @available_countries != [] and @mode != :preview do %>
|
<%= if @available_countries != [] and @mode != :preview do %>
|
||||||
<form phx-change="change_country">
|
<form action="/cart/country" method="post" phx-change="change_country">
|
||||||
|
<input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
|
||||||
<select
|
<select
|
||||||
name="country"
|
name="country"
|
||||||
class="delivery-select"
|
class="delivery-select"
|
||||||
@ -413,6 +414,9 @@ defmodule BerrypodWeb.ShopComponents.Cart do
|
|||||||
<option value={code} selected={code == @country_code}>{name}</option>
|
<option value={code} selected={code == @country_code}>{name}</option>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
|
<noscript>
|
||||||
|
<button type="submit" class="themed-button delivery-country-submit">Update</button>
|
||||||
|
</noscript>
|
||||||
</form>
|
</form>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span>{Berrypod.Shipping.country_name(@country_code)}</span>
|
<span>{Berrypod.Shipping.country_name(@country_code)}</span>
|
||||||
|
|||||||
@ -74,6 +74,19 @@ defmodule BerrypodWeb.CartController do
|
|||||||
|> redirect(to: ~p"/cart")
|
|> redirect(to: ~p"/cart")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates delivery country via form POST (no-JS fallback).
|
||||||
|
"""
|
||||||
|
def update_country(conn, %{"country" => code}) when is_binary(code) and code != "" do
|
||||||
|
conn
|
||||||
|
|> put_session("country_code", code)
|
||||||
|
|> redirect(to: ~p"/cart")
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_country(conn, _params) do
|
||||||
|
redirect(conn, to: ~p"/cart")
|
||||||
|
end
|
||||||
|
|
||||||
defp parse_quantity(str) when is_binary(str) do
|
defp parse_quantity(str) when is_binary(str) do
|
||||||
case Integer.parse(str) do
|
case Integer.parse(str) do
|
||||||
{qty, _} when qty > 0 -> qty
|
{qty, _} when qty > 0 -> qty
|
||||||
|
|||||||
@ -97,6 +97,7 @@ defmodule BerrypodWeb.Router do
|
|||||||
post "/cart/add", CartController, :add
|
post "/cart/add", CartController, :add
|
||||||
post "/cart/remove", CartController, :remove
|
post "/cart/remove", CartController, :remove
|
||||||
post "/cart/update", CartController, :update_item
|
post "/cart/update", CartController, :update_item
|
||||||
|
post "/cart/country", CartController, :update_country
|
||||||
end
|
end
|
||||||
|
|
||||||
# Health check (no auth, no theme loading — for load balancers and uptime monitors)
|
# Health check (no auth, no theme loading — for load balancers and uptime monitors)
|
||||||
|
|||||||
@ -108,4 +108,19 @@ defmodule BerrypodWeb.CartControllerTest do
|
|||||||
assert cart == []
|
assert cart == []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "POST /cart/country" do
|
||||||
|
test "saves country to session and redirects to /cart", %{conn: conn} do
|
||||||
|
conn = post(conn, ~p"/cart/country", %{"country" => "DE"})
|
||||||
|
|
||||||
|
assert redirected_to(conn) == "/cart"
|
||||||
|
assert get_session(conn, "country_code") == "DE"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handles missing country param", %{conn: conn} do
|
||||||
|
conn = post(conn, ~p"/cart/country", %{})
|
||||||
|
|
||||||
|
assert redirected_to(conn) == "/cart"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -106,6 +106,36 @@ defmodule BerrypodWeb.Shop.CartTest do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "no-JS fallback" do
|
||||||
|
setup [:create_cart_with_product]
|
||||||
|
|
||||||
|
test "country selector form has action for no-JS submission", %{
|
||||||
|
conn: conn,
|
||||||
|
variant: variant
|
||||||
|
} do
|
||||||
|
# Insert a shipping rate so the country selector renders
|
||||||
|
now = DateTime.utc_now() |> DateTime.truncate(:second)
|
||||||
|
pc = Berrypod.ProductsFixtures.provider_connection_fixture()
|
||||||
|
|
||||||
|
Berrypod.Repo.insert_all(Berrypod.Shipping.ShippingRate, [
|
||||||
|
[
|
||||||
|
blueprint_id: 1,
|
||||||
|
print_provider_id: 1,
|
||||||
|
country_code: "GB",
|
||||||
|
first_item_cost: 399,
|
||||||
|
additional_item_cost: 100,
|
||||||
|
provider_connection_id: pc.id,
|
||||||
|
inserted_at: now,
|
||||||
|
updated_at: now
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|
||||||
|
{:ok, view, _html} = conn |> conn_with_cart(variant.id) |> live(~p"/cart")
|
||||||
|
|
||||||
|
assert has_element?(view, "form[action='/cart/country'][method='post']")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Cart page title" do
|
describe "Cart page title" do
|
||||||
test "page title is Cart", %{conn: conn} do
|
test "page title is Cart", %{conn: conn} do
|
||||||
{:ok, _view, html} = live(conn, ~p"/cart")
|
{:ok, _view, html} = live(conn, ~p"/cart")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user