Release 0.80.14 - #3974
Merged
Merged
Release 0.80.14#3974
Conversation
…own (#3943) * refactor: price every caller from user_pricing user_flexible_price only answers whether a learner's financial assistance is approved. user_pricing answers what checkout will charge, carries the old answer field for field, and is the only source for the per-user discounts hq#11787 needs to display. The InfoBox hooks keep their gates and their behaviour: the displayed price still ignores an approved discount, which is surfaced as text. The dashboard enrollment dialog stops recomputing a discounted price in the browser from the aid record alone and shows the quote, so a learner holding an automatic or user-tied discount now sees what they will pay. Its query loses the financial-assistance-form condition for the same reason; without that, the quote would be ignored for most courses. The dialog does not gate on authentication: the quote endpoint rejects anonymous requests, and the dialog only opens from the dashboard, which is already behind an authenticated route. getFlexiblePriceForProduct and priceWithDiscount computed that price and go away with it. upgradeRunUrl goes too: it had no callers and was the last reference to the deprecated serializer's type. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat: quote every purchasable program and derive the applied-savings breakdown Widen the program pricing query so it fires for any signed-in learner on a purchasable program, not just one whose CMS page configures a financial assistance form. A program-child purchase credit exists independently of financial aid, so the aid form was never the right gate; it also conflated the form URL with the product's existence, hence the explicit product guard. The quote now yields `breakdown`: the one discount checkout would apply, split into rows that subtract, with the discount's kind resolved from the quote (`paid-amount-off` names a prior purchase; an id matching the flexible price is financial aid). Nothing renders it yet. `showsRange` collapses the advertised range to a single price once a learner has an approved flexible price. The range exists only to advertise the aid floor, so it is meaningless to someone already quoted against it. The CMS list-price comparison is untouched. The query opts out of the error boundary: the browser client throws 400/401/403, so a stale mitxonline session would otherwise replace the whole program page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: add the applied-savings card The paid offering box for a learner whose quote carries a discount: the program's price, what comes off it, and what checkout charges today. It replaces the Certificate Track card rather than decorating it, so it has no title, subtitle or feature bullets — a learner with a real number has no use for the advertised one. Nothing renders it yet. The rows are a description list so each label and amount are announced as a pair, and the deduction's sign is text ("minus") rather than colour alone. The discount's kind decides the sub-label and the info dialog: a credit names the purchase it came from, aid names itself, and anything else gets neither — a sale or a personal code has no rule behind it the learner could act on. TrackCard's shell/body pair becomes an exported CardSurface so both cards share one definition of the shaded surface and its fill behaviour; they stretch to a shared row height in the side-by-side layout and cannot drift apart. ProductSummary's LearnMoreDialog is exported and its href made optional, for a dialog whose description is the whole explanation. Extracting it instead would put UnderlinedLink in a cycle or break AboutSection's import of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: teach the enroll area to render an applied-savings breakdown EnrollOfferingBoxes takes an optional breakdown and, when it has one, replaces the Certificate Track card with AppliedSavingsCard under a heading row: the heading, the financial-aid indicator right-aligned beside it, and -- for a prior-purchase credit alone -- a line saying the purchase is applied to the full program price. A credit is the one discount the learner did not ask for, so it explains itself in the row; every other discount is left to the deduction row, which already names it. Courses pass nothing and are unaffected. The heading is "Choose Your Path" in the paid-plus-free layout, which already had one, and "Continue with full program" in the paid-only layout, which did not. The paid-only layout puts its heading inside the offering cell rather than emitting a full-row grid child: that layout is data-boxes="2", whose tablet grid is two columns with auto-flow, so a full-row heading would push the card out of the metadata block's row. InfoBoxGrid is untouched. The aid indicator moves onto the heading row only when a breakdown exists, since the card it otherwise lives in is not rendered at all. It cannot be pending there: a breakdown only exists once the same lookup has resolved, so FinancialAidPlaceholder stays behind in the card. FinancialAidLink moves to EnrollAreaParts and takes its text as children, because the heading row says "Financial aid applied" where the card says "Financial aid approved (visible at checkout)". Measured with the app's own font at the widths the offering cell reaches: the heading and the aside share a line at the ~346px desktop sidebar (308px of content in 346px) and the aside wraps to a line of its own at the ~268px tablet cell, where an auto left margin keeps it at the right edge — `space-between` would left-align it once alone on a line. "Continue with full program" stays on one line down to ~180px, so it never breaks mid-phrase at any width the grid produces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: show the program's own quote in its InfoBox ProgramEnrollArea passes the breakdown through, so a learner holding a purchase credit or an approved aid tier sees what checkout will charge instead of the advertised price. It also takes compactPrice from the hook's showsRange rather than recomputing toPriceRange(program), which would keep sizing the price slot for a range the learner no longer sees. No priceBlock suppression is needed: priceBlock reaches the DOM only through CertificateTrackCard, which is not rendered when a breakdown exists. useProgramEnrollment gains upgradeLabel, which relabels the paid action "Upgrade to Full Program". ProgramHeaderEnrollButton does not pass it, so the page-header CTA keeps the offering's own label; it runs its own hook with no pricing input, and making it follow would mean flipping its label after the quote resolves. The new label reaches fireEnrollCta verbatim, which splits nothing: enroll_cta_clicked slices on placement, enrollmentMode, resourceType and readableId, and carries label only for human readability. The existing suites already assert that a learner without a discount sees today's InfoBox — they quote every program at list price — so the new cases cover only the deduction state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: show a course's own quote in its InfoBox too Financial aid applies to a course exactly as it does to a program, so the breakdown reads the same on all three product pages. Only the purchase credit stays program-only: it is earned by buying one of the program's own courses and is worded throughout as an upgrade to the full program, which neither a course page nor a program presented as a course can say. `useCourseCertificatePrice` now derives the breakdown from the quote it already fetched, through the same helper the program hook uses, and its query is no longer gated on the CMS financial-assistance form — an automatic or user-tied discount prices a course that offers no aid at all. The label that differs stays with the caller: the card takes the product noun and names its first row "Course price" or "Program price". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: decide each InfoBox pricing rule in one place The paid offering box had four independent rules — a quote with a deduction, an aid form, a purchase credit, an approved aid tier — and several of them were decided in more than one file, or for one product type only. - The credit is decided once, in ProgramEnrollArea, which feeds the upgrade label, the heading and the note from a single boolean. EnrollOfferingBoxes takes plain paidHeading/paidNote props and no longer reads breakdown.kind; CourseEnrollArea passes neither. - The aid indicator is one component, FinancialAidIndicator, with one wording in both homes. "Financial aid approved (visible at checkout)" could only render when nothing was visible at checkout: any approved tier that lowers the price produces a breakdown, which replaces the card that carried it. - The course and program price hooks shared everything but how they found the product, so useCertificatePricing now owns the query, the aid object, the breakdown and the range collapse. The collapse for approved learners thereby applies to courses too, where it had been program-only. useCourseCertificatePrice is deleted. - OfferingHeadingRow returns null when it has nothing to carry; an empty row was still a flex item and opened the cell's 16px gap above the box for a paid-only sale with no aid form. - The (i) button gets aria-haspopup, aria-expanded and a name distinct from the row it explains; the popover gets an accessible name, which needed ol-components' Popover to accept aria-label/aria-labelledby. - Two redundant tests dropped; one added for the empty heading row and one for a quote whose discount takes nothing off, both mutation-checked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * If the user's income declaration is approved, but they don't qualify for financial aid, don't show them anything * fix: stop caching a learner's price quote as if it were ETL content The browser client defaults staleTime to the CDN TTL, justified for content that changes on the ETL's cadence. A user_pricing quote is not that: a program-child-purchase credit appears the moment the learner buys a child course. Nothing invalidates productsKeys, so the stale quote was served until the window elapsed. Matches baskets/queries.ts and useComplianceGate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: cite the constraint that actually makes paid-amount-off a credit The comment justified the classification by where a program-child-purchase discount attaches, but the code keys on discount_type. What rules out any other pairing is mitxonline's paid_amount_off_discount_shape CheckConstraint, so point at that instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: rename the dashboard pricing helper to setupCoursePricing It shared a name with ProductPages/test-utils/userPricing.ts's setupUserPricing while taking different arguments and meaning something different, so the two read as one helper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: open the applied-savings popover above the total it explains Popper's default placement put it over "Today's price" and its amount at every width, covering the one row the learner is reading. It still flips down when there is no room above. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test: cover the course noun on AppliedSavingsCard productNoun="course" was only exercised indirectly through the enroll-area suites, so FULL_PRICE_LABEL.course had no direct coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Carey P Gumaer <gumaerc@mit.edu>
…ges (#3954) Add a FAQ accordion to MIT Learn course/program product pages, driven by author-managed FAQs from the MITx Online Wagtail CMS (mitxonline#3961).
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* adding link to program letter in dashboard * ensure html is sanitized for program letter * correct lint lines * fix v1 spec * deleted hooks/programCertificates/index.ts and inlined the useQuery call in useProgramLetterMenuItem
OpenAPI Changes19 changes: 4 error, 0 warning, 15 info Unexpected changes? Ensure your branch is up-to-date with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Shankar Ambady
renovate[bot]
Zaman Afzal
Chris Chudzicki