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 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-03-13 13:34:22 +00:00
parent 09f55dfe67
commit a6e5db73c0
6 changed files with 49 additions and 10 deletions

View File

@ -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;

View File

@ -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)

View File

@ -212,6 +212,10 @@ defmodule BerrypodWeb.ShopComponents.Cart do
</p>
<% end %>
<p :if={Map.get(@item, :is_available) == false} class="cart-item-unavailable">
This item is currently unavailable
</p>
<div class="cart-item-actions">
<%= if @show_quantity_controls do %>
<form

View File

@ -16,11 +16,18 @@ defmodule BerrypodWeb.CheckoutController do
cart_items = Cart.get_from_session(get_session(conn))
hydrated = Cart.hydrate(cart_items)
if hydrated == [] do
cond do
hydrated == [] ->
conn
|> put_flash(:error, "Your basket is empty")
|> redirect(to: ~p"/cart")
else
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

View File

@ -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

View File

@ -553,7 +553,18 @@ defmodule BerrypodWeb.PageRenderer do
</div>
<.quantity_selector quantity={assigns[:quantity] || 1} in_stock={@product.in_stock} />
<.add_to_cart_button mode={@mode} />
<p
:if={assigns[:selected_variant] && !assigns[:selected_variant].is_available}
class="variant-unavailable-msg"
>
This option is currently unavailable
</p>
<.add_to_cart_button
mode={@mode}
disabled={assigns[:selected_variant] && !assigns[:selected_variant].is_available}
/>
</form>
</div>
</div>