From a6e5db73c077c2af1c86579441f1250e55623a68 Mon Sep 17 00:00:00 2001 From: jamey Date: Fri, 13 Mar 2026 13:34:22 +0000 Subject: [PATCH] prevent checkout with unavailable product variants - Include is_available flag in hydrated cart items - Show unavailable message on cart items and product page - Block add-to-cart for unavailable variants - Redirect back to cart with error if checkout has unavailable items Co-Authored-By: Claude Opus 4.5 --- assets/css/shop/components.css | 16 ++++++++++++++ lib/berrypod/cart.ex | 3 ++- .../components/shop_components/cart.ex | 4 ++++ .../controllers/checkout_controller.ex | 21 ++++++++++++------- lib/berrypod_web/live/shop/pages/product.ex | 2 +- lib/berrypod_web/page_renderer.ex | 13 +++++++++++- 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/assets/css/shop/components.css b/assets/css/shop/components.css index 4212cbb..36a8d04 100644 --- a/assets/css/shop/components.css +++ b/assets/css/shop/components.css @@ -781,6 +781,15 @@ font-weight: 600; } + /* ── Unavailable message ── */ + + .variant-unavailable-msg { + color: var(--t-sale-color); + font-size: var(--t-text-small); + font-weight: 500; + margin-bottom: 1rem; + } + /* ── Add to cart ── */ .atc-wrap { @@ -1709,6 +1718,13 @@ margin: 0; } + .cart-item-unavailable { + font-size: var(--t-text-caption); + color: var(--t-sale-color); + font-weight: 500; + margin: 0.25rem 0 0; + } + .cart-item-actions { display: flex; justify-content: space-between; diff --git a/lib/berrypod/cart.ex b/lib/berrypod/cart.ex index eea0477..76a5217 100644 --- a/lib/berrypod/cart.ex +++ b/lib/berrypod/cart.ex @@ -132,7 +132,8 @@ defmodule Berrypod.Cart do variant: format_variant_options(variant.options), price: variant.price, quantity: quantity, - image: variant_image_url(variant.product) + image: variant_image_url(variant.product), + is_available: variant.is_available } end end) diff --git a/lib/berrypod_web/components/shop_components/cart.ex b/lib/berrypod_web/components/shop_components/cart.ex index a5b4146..9f47ecb 100644 --- a/lib/berrypod_web/components/shop_components/cart.ex +++ b/lib/berrypod_web/components/shop_components/cart.ex @@ -212,6 +212,10 @@ defmodule BerrypodWeb.ShopComponents.Cart do

<% end %> +

+ This item is currently unavailable +

+
<%= if @show_quantity_controls do %>
put_flash(:error, "Your basket is empty") - |> redirect(to: ~p"/cart") - else - track_checkout_start(conn) - create_checkout(conn, hydrated) + cond do + hydrated == [] -> + conn + |> put_flash(:error, "Your basket is empty") + |> redirect(to: ~p"/cart") + + Enum.any?(hydrated, &(&1.is_available == false)) -> + conn + |> put_flash(:error, "Some items in your basket are no longer available") + |> redirect(to: ~p"/cart") + + true -> + track_checkout_start(conn) + create_checkout(conn, hydrated) end end end diff --git a/lib/berrypod_web/live/shop/pages/product.ex b/lib/berrypod_web/live/shop/pages/product.ex index 3d7d621..8a66dfa 100644 --- a/lib/berrypod_web/live/shop/pages/product.ex +++ b/lib/berrypod_web/live/shop/pages/product.ex @@ -90,7 +90,7 @@ defmodule BerrypodWeb.Shop.Pages.Product do def handle_event("add_to_cart", _params, socket) do variant = socket.assigns.selected_variant - if variant do + if variant && variant.is_available do cart = Cart.add_item(socket.assigns.raw_cart, variant.id, socket.assigns.quantity) if socket.assigns[:analytics_visitor_hash] do diff --git a/lib/berrypod_web/page_renderer.ex b/lib/berrypod_web/page_renderer.ex index 5f7e159..08a7ee8 100644 --- a/lib/berrypod_web/page_renderer.ex +++ b/lib/berrypod_web/page_renderer.ex @@ -553,7 +553,18 @@ defmodule BerrypodWeb.PageRenderer do
<.quantity_selector quantity={assigns[:quantity] || 1} in_stock={@product.in_stock} /> - <.add_to_cart_button mode={@mode} /> + +

+ This option is currently unavailable +

+ + <.add_to_cart_button + mode={@mode} + disabled={assigns[:selected_variant] && !assigns[:selected_variant].is_available} + />