A browser interface should be another caller
Course 02's calculateQuote function takes an order and returns component amounts. It does not import Node APIs or read document, so the browser can call the same function. Preserve that boundary.
Pause: If the page separately calculates a 10% discount to show a badge, what happens when the domain threshold changes but the badge code does not?
The two versions can disagree. Let one calculation produce the values used by every display element. The order object is the input; the quote is derived output; the DOM is its presentation.
Follow the data in one direction
Existing order data
-> calculateQuote(order)
-> valid quote OR explicit failure
-> render the matching state
-> user reads the page
Start with one render at startup. Change the sample input and reload to compare cases. Later modules will introduce editable inputs, events and state; when you add them, hide a previous quote until recalculation so an old result cannot look current. Do not read a formatted total back from the page to calculate tax: formatting belongs at the presentation boundary, not in the numeric input path.
Reuse the module
import { calculateQuote } from "./domain/pricing.js";
import { sampleOrder } from "./sample-order.js";
const quote = calculateQuote(sampleOrder);
console.assert(quote.totalCents === 16200);
For this fragment, put your Course 02 pricing and validation modules in a domain folder and create sample-order.js exporting the sampleOrder object defined in the lab. In HTML, type="module" enables imports. Serve your practice folder through a local HTTP preview rather than opening it with a file URL; module loading has origin and content-type requirements. See MDN's module guide for the platform details.
Put text into text nodes
const nameElement = document.querySelector("#customer-name");
nameElement.textContent = sampleOrder.customer.name;
QuerySelector returns the first match or null. A missing required element is a mismatch between your HTML and JavaScript; diagnose it rather than letting the page silently omit important information.
TextContent treats the value as text instead of parsing it as markup. For a customer name, that is the intended behavior. Do not interpolate external names into innerHTML merely for convenience. MDN documents the distinction.
A test name like <strong>Sara</strong> should appear as literal text, not turn into bold markup. This small counterexample tests the boundary between data and document structure.
Format at the boundary
For this fictional pricing exercise, divide cents by 100 and display two decimal places followed by "units." You can use Intl.NumberFormat for numeric display, with two minimum and maximum fraction digits. Formatting does not change the stored cents or the rounding policy already applied by calculateQuote.
If a real currency were introduced, its identity and display conventions would need to be specified. Do not invent a currency symbol for unspecified money.
Treat failure as a different state
A naive render function updates the total only on success. If it later receives an invalid order, the old valid amount may remain visible. The page now contradicts its error message.
Your render path should clear previous items and amounts, hide the old breakdown and then render either the new valid result or a failure explanation. The user should never need to guess which total belongs to which state.
This is our first encounter with state-driven rendering: determine the outcome, then make the visible page agree with it. It is not yet a complete state-management system.
Independent exercise: a dangerous shortcut
Someone suggests catching every quote error and displaying 0.00. Explain the problem, then propose a check that would detect it. Also test a premium order at exactly 10,000 cents.
Correction and reasoning
Zero falsely communicates a valid free quote. A rejected order should show an unavailable state with no successful breakdown. Exactly 10,000 cents remains ineligible for the discount and totals 12,000 cents after exercise tax. That boundary must agree in the domain tests and the screen.
Review
You should be able to point to the code responsible for input, pricing, formatting and DOM updates. If changing a heading requires touching a discount rule, the responsibilities have become entangled.