The server can refuse. The Lamp has only one in stock: once it is in the cart, a second POST /api/cart for it answers 409 with {"error": "Only 1 left"}. For fetch that is still an answer, so it doesn't throw. Only response.ok, which is false for any 4xx or 5xx status, tells you the server said no.
So check response.ok before you use the data, and show the server's own message. For example, an order form could do:
const data = await response.json();
if (!response.ok) {
orderNote.textContent = data.error;
return;
}
The product cards are drawn again by render on every change, so a note added to a card by hand would vanish. Keep the message, and the id of the product it is about, in a variable problem, and let productCard draw it under the right card. One more trap: while a request waits, a second click on the same button sends a second request. Disable the button when it is clicked; render draws a fresh one when the answer comes.
The check adds the Lamp, clicks it again and prints the screen while that second request waits. Your page must show:
> click "Add to cart" in "Lamp"
request: POST /api/cart {"product_id": 3, "quantity": 1} -> 201
+ item: Lamp x 1 $29
> click "Add to cart" in "Lamp"
request: POST /api/cart {"product_id": 3, "quantity": 1} ...
screen while waiting:
item: Lamp $29
button: Add to cart (disabled)
answer: POST /api/cart {"product_id": 3, "quantity": 1} -> 409
item: Lamp $29
- button: Add to cart (disabled)
+ button: Add to cart
+ text: Only 1 left
Your task: in addToCart, when the answer is not ok, keep the product's id and data.error in problem, call render and stop; in productCard, add a p with the message to the card it is about; and disable the clicked button.
Assignment
Follow the Coding Tutorial to show the server's message under the product it refused, and to keep a double click from sending two requests.
Hint
The 409 answer has no items. Return before cart = data.items;, or cart becomes undefined and render throws on cart.map.
Free plan: 30 tutor messages. PRO is unlimited.
