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:
parent
09f55dfe67
commit
a6e5db73c0
@ -781,6 +781,15 @@
|
|||||||
font-weight: 600;
|
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 ── */
|
/* ── Add to cart ── */
|
||||||
|
|
||||||
.atc-wrap {
|
.atc-wrap {
|
||||||
@ -1709,6 +1718,13 @@
|
|||||||
margin: 0;
|
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 {
|
.cart-item-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@ -132,7 +132,8 @@ defmodule Berrypod.Cart do
|
|||||||
variant: format_variant_options(variant.options),
|
variant: format_variant_options(variant.options),
|
||||||
price: variant.price,
|
price: variant.price,
|
||||||
quantity: quantity,
|
quantity: quantity,
|
||||||
image: variant_image_url(variant.product)
|
image: variant_image_url(variant.product),
|
||||||
|
is_available: variant.is_available
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@ -212,6 +212,10 @@ defmodule BerrypodWeb.ShopComponents.Cart do
|
|||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<p :if={Map.get(@item, :is_available) == false} class="cart-item-unavailable">
|
||||||
|
This item is currently unavailable
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="cart-item-actions">
|
<div class="cart-item-actions">
|
||||||
<%= if @show_quantity_controls do %>
|
<%= if @show_quantity_controls do %>
|
||||||
<form
|
<form
|
||||||
|
|||||||
@ -16,13 +16,20 @@ defmodule BerrypodWeb.CheckoutController do
|
|||||||
cart_items = Cart.get_from_session(get_session(conn))
|
cart_items = Cart.get_from_session(get_session(conn))
|
||||||
hydrated = Cart.hydrate(cart_items)
|
hydrated = Cart.hydrate(cart_items)
|
||||||
|
|
||||||
if hydrated == [] do
|
cond do
|
||||||
conn
|
hydrated == [] ->
|
||||||
|> put_flash(:error, "Your basket is empty")
|
conn
|
||||||
|> redirect(to: ~p"/cart")
|
|> put_flash(:error, "Your basket is empty")
|
||||||
else
|
|> redirect(to: ~p"/cart")
|
||||||
track_checkout_start(conn)
|
|
||||||
create_checkout(conn, hydrated)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -90,7 +90,7 @@ defmodule BerrypodWeb.Shop.Pages.Product do
|
|||||||
def handle_event("add_to_cart", _params, socket) do
|
def handle_event("add_to_cart", _params, socket) do
|
||||||
variant = socket.assigns.selected_variant
|
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)
|
cart = Cart.add_item(socket.assigns.raw_cart, variant.id, socket.assigns.quantity)
|
||||||
|
|
||||||
if socket.assigns[:analytics_visitor_hash] do
|
if socket.assigns[:analytics_visitor_hash] do
|
||||||
|
|||||||
@ -553,7 +553,18 @@ defmodule BerrypodWeb.PageRenderer do
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<.quantity_selector quantity={assigns[:quantity] || 1} in_stock={@product.in_stock} />
|
<.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>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user