anonymous checkout - #3709
Open
gumaerc wants to merge 6 commits into
Open
Conversation
OpenAPI ChangesNo changes detected Unexpected changes? Ensure your branch is up-to-date with |
3 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR begins enabling anonymous paid checkout flows by handing unauthenticated users off to MITx Online’s basket/cart flow (gated behind a PostHog feature flag) and ensuring the anonymous basket identifier is preserved across the redirect.
Changes:
- Add
anonymous-checkoutfeature flag and gate paid enrollment handoff behavior in course/program enrollment hooks. - Update basket/cart redirect logic to append
anonymous_basket_idwhen applicable, and adjust React Query invalidation to avoid hitting checkout payload for anonymous baskets. - Update/extend frontend tests to account for the new auth/flag behavior and additional Learn-auth mocking.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Updates lock entries to pull @mitodl/mitxonline-api-axios from a GitHub tarball URL. |
| frontends/main/src/page-components/EnrollmentDialogs/CourseEnrollmentDialog.test.tsx | Mocks Learn auth state needed by updated basket hooks. |
| frontends/main/src/common/mitxonline/useReplaceBasketItem.ts | Appends anonymous_basket_id to MITx Online cart redirect URL. |
| frontends/main/src/common/mitxonline/useReplaceBasketItem.test.tsx | Adds tests validating anonymous basket redirect query param behavior. |
| frontends/main/src/common/feature_flags.ts | Adds AnonymousCheckout flag constant. |
| frontends/main/src/app-pages/ProductPages/useProgramEnrollment.ts | Gates anonymous paid handoff behavior on feature flag. |
| frontends/main/src/app-pages/ProductPages/useProgramEnrollment.test.tsx | Tests paid unauthenticated behavior with flag on/off. |
| frontends/main/src/app-pages/ProductPages/useCourseEnrollment.ts | Gates anonymous paid handoff behavior on feature flag. |
| frontends/main/src/app-pages/ProductPages/useCourseEnrollment.test.tsx | Tests paid unauthenticated behavior with flag on/off. |
| frontends/main/src/app-pages/DashboardPage/CoursewareDisplay/*.test.tsx | Adds Learn-auth mocking required by basket hook changes. |
| frontends/main/package.json | Switches @mitodl/mitxonline-api-axios dependency to a GitHub tarball URL. |
| frontends/api/src/mitxonline/hooks/baskets/index.ts | Avoids invalidating checkout-payload query for anonymous baskets by checking Learn auth state. |
| frontends/api/package.json | Switches @mitodl/mitxonline-api-axios dependency to a GitHub tarball URL. |
Suppressed comments (1)
frontends/main/src/common/mitxonline/useReplaceBasketItem.test.tsx:138
- Same as the earlier test: this
mockImplementationOnceoverride re-typesopts.onSuccessto accept a basket argument, which may be incompatible with the originalmutatemock type and fail type-checking. Loosen/cast the override types so the mock remains assignable.
mutate.mockImplementationOnce(
(_productId: number, opts?: { onSuccess?: (b: unknown) => void }) =>
opts?.onSuccess?.({ id: 9, user: 1, anonymous_id: null }),
)
| "@mitodl/course-search-utils": "^3.5.2", | ||
| "@mitodl/hacksnack": "^0.1.0", | ||
| "@mitodl/mitxonline-api-axios": "2026.7.22", | ||
| "@mitodl/mitxonline-api-axios": "https://github.com/mitodl/mitxonline-api-clients/raw/c6157f4f8c6991b080a76d3d140e6114076aeab8/src/typescript/mitxonline-api-axios/package.tgz", |
| "dependencies": { | ||
| "@mitodl/mit-learn-api-axios": "2026.7.22", | ||
| "@mitodl/mitxonline-api-axios": "2026.7.22", | ||
| "@mitodl/mitxonline-api-axios": "https://github.com/mitodl/mitxonline-api-clients/raw/c6157f4f8c6991b080a76d3d140e6114076aeab8/src/typescript/mitxonline-api-axios/package.tgz", |
gumaerc
force-pushed
the
cg/anonymous-checkout
branch
5 times, most recently
from
August 5, 2026 17:54
85fdc58 to
1487741
Compare
ChristopherChudzicki
requested changes
Aug 6, 2026
Contributor
There was a problem hiding this comment.
👍 Working well, I am going to make a few changes, primarily (1) and (2) below.
- Revert the auth check on the basket invalidations — restore the unconditional
invalidateQueriesinuseAddToBasketanduseClearBasket.[^1]- Nothing should be subscribe without authentication: UI either doesn't load that, or it would be gated by
enabled. - If something actually is subscribed, it should be invalidated.
- Aside: Nothing actually uses that query right now at all.
- Plus the gating as-is is on Learn session; if it's gated at all, it should be gated on MITxOnline session
- Nothing should be subscribe without authentication: UI either doesn't load that, or it would be gated by
- Test what the PR actually does — add a test that feeds a basket carrying an
anonymous_idthrough the realuseReplaceBasketItemand asserts the redirect URL has?anonymous_basket_id=. Nothing covers that seam today.[^3] - Share pending state across basket mutation instances —
CoursePage.tsx:52andCourseEnrollArea.tsx:22each own a separateuseReplaceBasketItemand each disables only on its own pending state, so clicking one CTA then the other starts two clear→add chains.[^2]CourseEnrollmentDialog.tsx:271needs the same treatment; it'sdisabled={!enabled}today, so a plain double-click does it. - Add
isErrortouseEnrollmentHandler— it returnsisPendingbut notisError(lines 175–181), andUnenrolledCourseCard.tsx:51consumes onlyisPending, so a failed dashboard upgrade shows the user nothing at all.
ChristopherChudzicki
changed the base branch from
main
to
update-mitxonline-api-client
August 6, 2026 21:32
ChristopherChudzicki
force-pushed
the
cg/anonymous-checkout
branch
from
August 6, 2026 21:32
ad56f7a to
620a00e
Compare
ChristopherChudzicki
force-pushed
the
cg/anonymous-checkout
branch
from
August 7, 2026 14:05
620a00e to
5f1a091
Compare
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.
What are the relevant tickets?
https://github.com/mitodl/hq/issues/12530
Description (What does it do?)
Lets a logged-out learner start a paid purchase without creating an account first. Behind the
anonymous-checkoutfeature flag, clicking a paid enroll CTA while unauthenticated now hands off directly to the MITx Online basket/checkout instead of showing the signup popover; account creation happens later in the MITx Online flow (Review → Account → Verify → Payment).AnonymousCheckout(anonymous-checkout), off by default → no behavior change. With the flag off, an unauthenticated paid (or free) click still routes toonRequireSignup, exactly as today.useCourseEnrollment,useProgramEnrollment): the auth guard is now!isAuthenticated && (kind === "free" || !anonymousCheckoutEnabled) → onRequireSignup. With the flag on, an unauthenticated paid click proceeds to the basket handoff; free enrollment still requires an account (there is no anonymous audit/free enrollment).useReplaceBasketItem: threads the created basket'sanonymous_idinto the/cart/redirect as ananonymous_basket_idquery param. Django's session cookie for the anonymous basket is host-only and can't cross from Learn's proxied API host to MITx Online's own domain, so the id is handed off explicitly in the URL (MITx Online'sAnonymousBasketHandoffMiddlewareadopts it into the session and strips it).useAddToBasket/useClearBasket): skipbasketStatequery invalidation when unauthenticated.basketStatehits the checkout-payload endpoint, which creates a real order against the basket's purchaser; an anonymous basket has no purchaser, so invalidation must wait until after the anonymous→authenticated conversion.enroll/begin_checkoutanalytics on the paid path.How can this be tested?
MITOL_PAYMENT_GATEWAY_CYBERSOURCE_as well asECOMMERCE_DEFAULT_PAYMENT_GATEWAY="Cybersource"anonymous-checkoutfeature flag enabled@mitodl/mitxonline-api-axiospackage withdocker compose exec yarn up @mitodl/mitxonline-api-axios@https://github.com/mitodl/mitxonline-api-clients/raw/954216380a8d7f09f9b7bfa00c09d09b28bd4cfe/src/typescript/mitxonline-api-axios/package.tgzAdditional Context
@mitodl/mitxonline-api-axiosis pinned to a branch build of the pending MITx Online release (foranonymous_idand the new basket types). This must be swapped for the official published version once that release ships.sso_organization_idfield (MITx Online #3807), which is required onOrganizationPage. Adopting the client therefore also requires a small test-fixture update for the org factory/tests — coupled to the client bump, not to anonymous-checkout behavior. (Runtime already tolerates it viaorgUuid.ts, added earlier in feat(b2b): org analytics dashboard for the manager surface #3679.)Checklist:
@mitodl/mitxonline-api-axiospin for the official release build before/at releaseanonymous-checkoutPostHog flag exists in each environment