Shipping Options at Checkout
A shopper is one step from buying. The last screen of checkout lets them pick how fast the parcel should arrive, and it has to get three things right: the price of each speed, the total they will pay, and placing the order exactly once.
Build the delivery step of the checkout. The cart's subtotal is fixed at $42.50 (SUBTOTAL_CENTS in src/App.jsx).
Requirements
- On load, fetch
GET /api/shipping-options. It answers{ "options": [{ "id", "label", "price", "days" }] }, withpricein cents. - While it loads, show the text
Loading delivery options. - Then show a
fieldsetwhose legend isDelivery speed, with one radio button per option. Each radio's label starts with the option's label (Standard,Express,Next day) and also shows:- its price:
Freewhen it costs nothing, otherwise dollars with two decimals, like$7.99; - its arrival:
Arrives in 5 business days, orArrives in 1 business dayfor one day.
- its price:
- The cheapest option is selected when the options arrive, wherever it is in the list.
- A summary shows
Subtotal($42.50), then the shipping cost in an<output>labelledShipping cost(Freeor the price) and the total in an<output>labelledOrder total(subtotal plus shipping, always as dollars). - A
Place orderbutton is disabled until the options have loaded. Clicking it sendsPOST /api/orderswith the JSON body{ "shippingOptionId": "<id of the selected option>" }.- On success the server answers
{ "orderId": "112-4410" }: showOrder 112-4410 placed.The order must be sent only once, even on a double click. - On failure show an alert,
We couldn't place your order. Please try again., and enable the button again so the shopper can retry.
- On success the server answers
The setup
The files open on a skeleton. Build the behaviour the requirements describe.
- src/main.jsx
- src/App.jsx
- src/styles.css
The preview has no network. fetch is answered by this problem's API:
- GET /api/shipping-options
- POST /api/orders
Follow-up: Product wants to show "Order in the next 2 hours to get it tomorrow" under Next day. Where does that countdown live, and how do you keep it from re-rendering the whole checkout every second?
- React with JavaScript and plain CSS; every file is editable. - Keep money in integer cents and only format it for display. - Use real radio buttons in one group, inside a `fieldset` with a `legend`. - The two figures in the summary are `<output>` elements with the `aria-label`s `Shipping cost` and `Order total`.
- Views
- 4