Fix sold-out logic: only mark product sold out when all variants are exhausted

Previously, if any single variant hit 0 stock, the whole product card
would show as sold out and block ordering. Now it checks all tracked
variants — the product is only sold out when every variant is unavailable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chris 2026-06-18 10:59:41 -04:00
parent 699c5cbaa1
commit 904fa91bad

View File

@ -10,15 +10,18 @@ interface Props {
item: CatalogItem item: CatalogItem
} }
/** Lowest stock count across tracked variations. null = nothing tracked. */
function lowestTrackedInventory(item: CatalogItem): number | null {
const tracked = item.variations.filter((v) => v.inventory !== null)
if (!tracked.length) return null
return Math.min(...tracked.map((v) => v.inventory as number))
}
const LOW_STOCK_THRESHOLD = 5 const LOW_STOCK_THRESHOLD = 5
function stockStats(item: CatalogItem): { soldOut: boolean; lowStock: boolean; lowestAvailable: number | null } {
const tracked = item.variations.filter((v) => v.inventory !== null)
if (!tracked.length) return { soldOut: false, lowStock: false, lowestAvailable: null }
const allSoldOut = tracked.every((v) => (v.inventory as number) <= 0)
const available = tracked.filter((v) => (v.inventory as number) > 0)
const lowestAvailable = available.length ? Math.min(...available.map((v) => v.inventory as number)) : null
const lowStock = lowestAvailable !== null && lowestAvailable <= LOW_STOCK_THRESHOLD
return { soldOut: allSoldOut, lowStock, lowestAvailable }
}
export default function ProductCard({ item }: Props) { export default function ProductCard({ item }: Props) {
const [showPicker, setShowPicker] = useState(false) const [showPicker, setShowPicker] = useState(false)
// Prefer admin-set colorMax; fall back to name-based heuristic // Prefer admin-set colorMax; fall back to name-based heuristic
@ -26,9 +29,7 @@ export default function ProductCard({ item }: Props) {
? (item.colorMax !== null && item.colorMax !== undefined ? item.colorMax : maxColorsFor(item.name)) ? (item.colorMax !== null && item.colorMax !== undefined ? item.colorMax : maxColorsFor(item.name))
: null : null
const stock = lowestTrackedInventory(item) const { soldOut, lowStock, lowestAvailable: stock } = stockStats(item)
const soldOut = stock !== null && stock <= 0
const lowStock = stock !== null && stock > 0 && stock <= LOW_STOCK_THRESHOLD
const priceDisplay = item.price ? `From ${fmt(item.price)}` : 'Custom quote' const priceDisplay = item.price ? `From ${fmt(item.price)}` : 'Custom quote'