@edx/frontend-app-subscription-checkout 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/LICENSE +661 -0
  2. package/README.rst +235 -0
  3. package/dist/Main.d.ts +3 -0
  4. package/dist/Main.js +15 -0
  5. package/dist/Main.js.map +1 -0
  6. package/dist/app.d.ts +3 -0
  7. package/dist/app.js +13 -0
  8. package/dist/app.js.map +1 -0
  9. package/dist/checkoutPage/CheckoutPage.d.ts +3 -0
  10. package/dist/checkoutPage/CheckoutPage.js +30 -0
  11. package/dist/checkoutPage/CheckoutPage.js.map +1 -0
  12. package/dist/components/BrandMarks/BrandMarks.d.ts +3 -0
  13. package/dist/components/BrandMarks/BrandMarks.js +9 -0
  14. package/dist/components/BrandMarks/BrandMarks.js.map +1 -0
  15. package/dist/components/CartSummary/CartSummary.d.ts +21 -0
  16. package/dist/components/CartSummary/CartSummary.js +30 -0
  17. package/dist/components/CartSummary/CartSummary.js.map +1 -0
  18. package/dist/components/CartSummary/Messages.d.ts +73 -0
  19. package/dist/components/CartSummary/Messages.js +76 -0
  20. package/dist/components/CartSummary/Messages.js.map +1 -0
  21. package/dist/components/Checkout/Checkout.d.ts +4 -0
  22. package/dist/components/Checkout/Checkout.js +40 -0
  23. package/dist/components/Checkout/Checkout.js.map +1 -0
  24. package/dist/components/CheckoutGate/CheckoutGate.d.ts +7 -0
  25. package/dist/components/CheckoutGate/CheckoutGate.js +35 -0
  26. package/dist/components/CheckoutGate/CheckoutGate.js.map +1 -0
  27. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.d.ts +9 -0
  28. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js +31 -0
  29. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js.map +1 -0
  30. package/dist/components/CourseEnrollmentCard/Messages.d.ts +33 -0
  31. package/dist/components/CourseEnrollmentCard/Messages.js +35 -0
  32. package/dist/components/CourseEnrollmentCard/Messages.js.map +1 -0
  33. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.d.ts +13 -0
  34. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js +11 -0
  35. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js.map +1 -0
  36. package/dist/components/EnrollmentSummary/EnrollmentSummary.d.ts +15 -0
  37. package/dist/components/EnrollmentSummary/EnrollmentSummary.js +21 -0
  38. package/dist/components/EnrollmentSummary/EnrollmentSummary.js.map +1 -0
  39. package/dist/components/EnrollmentSummary/Messages.d.ts +33 -0
  40. package/dist/components/EnrollmentSummary/Messages.js +35 -0
  41. package/dist/components/EnrollmentSummary/Messages.js.map +1 -0
  42. package/dist/components/PaymentFields/PaymentFields.d.ts +9 -0
  43. package/dist/components/PaymentFields/PaymentFields.js +7 -0
  44. package/dist/components/PaymentFields/PaymentFields.js.map +1 -0
  45. package/dist/components/PaymentForm/Messages.d.ts +88 -0
  46. package/dist/components/PaymentForm/Messages.js +95 -0
  47. package/dist/components/PaymentForm/Messages.js.map +1 -0
  48. package/dist/components/PaymentForm/PaymentForm.d.ts +21 -0
  49. package/dist/components/PaymentForm/PaymentForm.js +69 -0
  50. package/dist/components/PaymentForm/PaymentForm.js.map +1 -0
  51. package/dist/components/StatusScreens/Messages.d.ts +103 -0
  52. package/dist/components/StatusScreens/Messages.js +108 -0
  53. package/dist/components/StatusScreens/Messages.js.map +1 -0
  54. package/dist/components/StatusScreens/StatusScreens.d.ts +23 -0
  55. package/dist/components/StatusScreens/StatusScreens.js +25 -0
  56. package/dist/components/StatusScreens/StatusScreens.js.map +1 -0
  57. package/dist/constants.d.ts +59 -0
  58. package/dist/constants.js +276 -0
  59. package/dist/constants.js.map +1 -0
  60. package/dist/data/hooks/keys.d.ts +14 -0
  61. package/dist/data/hooks/keys.js +15 -0
  62. package/dist/data/hooks/keys.js.map +1 -0
  63. package/dist/data/hooks/useCheckout.d.ts +57 -0
  64. package/dist/data/hooks/useCheckout.js +249 -0
  65. package/dist/data/hooks/useCheckout.js.map +1 -0
  66. package/dist/data/hooks/useCheckoutGate.d.ts +15 -0
  67. package/dist/data/hooks/useCheckoutGate.js +39 -0
  68. package/dist/data/hooks/useCheckoutGate.js.map +1 -0
  69. package/dist/data/hooks/useCheckoutMutations.d.ts +16 -0
  70. package/dist/data/hooks/useCheckoutMutations.js +131 -0
  71. package/dist/data/hooks/useCheckoutMutations.js.map +1 -0
  72. package/dist/data/hooks/useCheckoutQueries.d.ts +30 -0
  73. package/dist/data/hooks/useCheckoutQueries.js +97 -0
  74. package/dist/data/hooks/useCheckoutQueries.js.map +1 -0
  75. package/dist/data/services/subs/urls.d.ts +2 -0
  76. package/dist/data/services/subs/urls.js +4 -0
  77. package/dist/data/services/subs/urls.js.map +1 -0
  78. package/dist/i18n/index.d.ts +1 -0
  79. package/dist/i18n/index.js +2 -0
  80. package/dist/i18n/index.js.map +1 -0
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +3 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/messages.d.ts +8 -0
  85. package/dist/messages.js +10 -0
  86. package/dist/messages.js.map +1 -0
  87. package/dist/routes.d.ts +18 -0
  88. package/dist/routes.js +67 -0
  89. package/dist/routes.js.map +1 -0
  90. package/dist/slots/ExampleSlot/ExampleSlot.d.ts +3 -0
  91. package/dist/slots/ExampleSlot/ExampleSlot.js +6 -0
  92. package/dist/slots/ExampleSlot/ExampleSlot.js.map +1 -0
  93. package/dist/slots.d.ts +3 -0
  94. package/dist/slots.js +7 -0
  95. package/dist/slots.js.map +1 -0
  96. package/dist/style.scss +14 -0
  97. package/dist/styles/components/brandMarks.scss +54 -0
  98. package/dist/styles/components/cartSummary.scss +18 -0
  99. package/dist/styles/components/checkout.scss +29 -0
  100. package/dist/styles/components/checkoutStepper.scss +9 -0
  101. package/dist/styles/components/courseEnrollmentCard.scss +38 -0
  102. package/dist/styles/components/edxUnlimitedBanner.scss +138 -0
  103. package/dist/styles/components/enrollmentSummary.scss +13 -0
  104. package/dist/styles/components/paymentFields.scss +15 -0
  105. package/dist/styles/components/paymentForm.scss +105 -0
  106. package/dist/styles/components/statusScreens.scss +29 -0
  107. package/dist/styles/components/successScreen.scss +0 -0
  108. package/dist/types.d.ts +222 -0
  109. package/dist/types.js +2 -0
  110. package/dist/types.js.map +1 -0
  111. package/dist/utils/auth.d.ts +7 -0
  112. package/dist/utils/auth.js +28 -0
  113. package/dist/utils/auth.js.map +1 -0
  114. package/dist/utils/billingDetails.d.ts +30 -0
  115. package/dist/utils/billingDetails.js +47 -0
  116. package/dist/utils/billingDetails.js.map +1 -0
  117. package/dist/utils/bootstrapApi.d.ts +20 -0
  118. package/dist/utils/bootstrapApi.js +142 -0
  119. package/dist/utils/bootstrapApi.js.map +1 -0
  120. package/dist/utils/cartApi.d.ts +16 -0
  121. package/dist/utils/cartApi.js +118 -0
  122. package/dist/utils/cartApi.js.map +1 -0
  123. package/dist/utils/checkout.d.ts +6 -0
  124. package/dist/utils/checkout.js +28 -0
  125. package/dist/utils/checkout.js.map +1 -0
  126. package/dist/utils/fetchActiveSubscriptions.d.ts +4 -0
  127. package/dist/utils/fetchActiveSubscriptions.js +36 -0
  128. package/dist/utils/fetchActiveSubscriptions.js.map +1 -0
  129. package/dist/utils/fetchBillingPlans.d.ts +2 -0
  130. package/dist/utils/fetchBillingPlans.js +48 -0
  131. package/dist/utils/fetchBillingPlans.js.map +1 -0
  132. package/dist/utils/graphqlClient.d.ts +16 -0
  133. package/dist/utils/graphqlClient.js +39 -0
  134. package/dist/utils/graphqlClient.js.map +1 -0
  135. package/dist/utils/index.d.ts +3 -0
  136. package/dist/utils/index.js +17 -0
  137. package/dist/utils/index.js.map +1 -0
  138. package/dist/utils/provision.d.ts +25 -0
  139. package/dist/utils/provision.js +95 -0
  140. package/dist/utils/provision.js.map +1 -0
  141. package/dist/utils/queries.d.ts +35 -0
  142. package/dist/utils/queries.js +168 -0
  143. package/dist/utils/queries.js.map +1 -0
  144. package/dist/utils/stripe.d.ts +7 -0
  145. package/dist/utils/stripe.js +43 -0
  146. package/dist/utils/stripe.js.map +1 -0
  147. package/dist/widgets/ExampleHeader/app.d.ts +3 -0
  148. package/dist/widgets/ExampleHeader/app.js +19 -0
  149. package/dist/widgets/ExampleHeader/app.js.map +1 -0
  150. package/dist/widgets/ExampleHeader/index.d.ts +1 -0
  151. package/dist/widgets/ExampleHeader/index.js +2 -0
  152. package/dist/widgets/ExampleHeader/index.js.map +1 -0
  153. package/package.json +85 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCheckout.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckout.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n useCallback, useEffect, useMemo, useRef, useState,\n} from 'react';\nimport type { Ref } from 'react';\nimport type { BillingCycle } from '../../types';\nimport { createCheckoutClient } from '../../utils/checkout';\nimport { loadStripe } from '../../utils/stripe';\nimport {\n STATUS, STATUS_LABELS, STRIPE_ELEMENT_OPTS, phaseFor, DEFAULTS,\n} from '../../constants';\nimport type {\n Status, Phase, Cart, BillingInfo, CheckoutClient, StripeLike, StripeElementLike,\n StripeElementsLike, BillingPlan, CheckoutConsent,\n} from '../../types';\nimport {\n useCartStatusQuery, useSubscriptionIdQuery, useBillingPlansQuery,\n useActiveSubscriptionsQuery, useViaxSessionQuery, useCourseDetailQuery,\n} from './useCheckoutQueries';\nimport type { EdxSessionResult } from '../../utils/provision';\nimport { useCheckoutMutations } from './useCheckoutMutations';\n\n/**\n * Read ?course_run_key= from the current URL.\n * Avoid URLSearchParams — it treats bare `+` as a space, which would turn\n * HarvardX+CS50+X into \"HarvardX CS50 X\". decodeURIComponent keeps `+` intact.\n */\nfunction getCourseRunKeyFromUrl(): string | null {\n if (typeof window === 'undefined') return null;\n const match = /[?&]course_run_key=([^&]*)/.exec(window.location.search);\n if (!match) return null;\n try {\n // Preserve literal `+` (treat as %2B) then decode %XX sequences.\n return decodeURIComponent(match[1].replace(/\\+/g, '%2B')).trim() || null;\n } catch {\n return match[1].trim() || null;\n }\n}\n\nexport interface UseCheckoutOptions {\n apiUrl?: string,\n edxSessionUrl?: string,\n stripePublishableKey?: string,\n onComplete?: (subscriptionBiId: string | null) => void,\n /** Country code resolved by CheckoutGate — used to show/hide the UK/CA extra checkbox. */\n userCountry?: string | null,\n /**\n * Course run key from the URL (e.g. course-v1:HarvardX+CS50+X).\n * When omitted, read from ?course_run_key=.\n */\n courseRunKey?: string | null,\n}\n\nexport interface UseCheckoutResult {\n phase: Phase,\n status: Status | null,\n statusLabel: string,\n stripeReady: boolean,\n /** True once the Stripe card Element iframe is fully initialised and interactive. */\n cardReady: boolean,\n notConfigured: boolean,\n showBanner: boolean,\n dismissBanner: () => void,\n error: string,\n clearError: () => void,\n cardError: string,\n lastComment: string,\n /** Full subscription details including card last 4 — available after SUBSCRIPTION_CREATED. */\n subscriptionDetails: import('../../types').SubscriptionDetails | null,\n billing: BillingInfo,\n setField: (field: keyof BillingInfo, value: string) => void,\n numberMountRef: Ref<HTMLDivElement>,\n expiryMountRef: Ref<HTMLDivElement>,\n cvcMountRef: Ref<HTMLDivElement>,\n submitting: boolean,\n /** True from Place order click until a terminal status is reached. */\n processingSubscription: boolean,\n placeOrder: (consent: CheckoutConsent) => void,\n /** Billing plans fetched on mount — includes prices for display in CartSummary. */\n billingPlans: BillingPlan[],\n /** Live active subscriber count for display in CartSummary. */\n activeSubscriberCount: number | null,\n /** Currently selected billing cycle. */\n selectedCycle: BillingCycle,\n /** Switch between monthly and annual billing. */\n setCycle: (cycle: BillingCycle) => void,\n /** True once GET /edx-session has returned and the viax token is set. */\n sessionReady: boolean,\n /** ISO 3166-1 alpha-2 country code — passed in from CheckoutGate for the UK/CA checkbox. */\n userCountry: string | null,\n /** Course details when arrived via ?course_run_key=; null for standard checkout. */\n course: import('../../types').CourseDetail | null,\n}\n\nexport default function useCheckout(options: UseCheckoutOptions = {}): UseCheckoutResult {\n const {\n apiUrl = DEFAULTS.apiUrl,\n edxSessionUrl,\n stripePublishableKey,\n onComplete,\n userCountry = null,\n courseRunKey: courseRunKeyProp,\n } = options;\n\n const courseRunKey = useMemo(\n () => courseRunKeyProp ?? getCourseRunKeyFromUrl(),\n [courseRunKeyProp],\n );\n\n const client = useMemo<CheckoutClient | null>(() => {\n if (!apiUrl) return null;\n return createCheckoutClient({ apiUrl });\n }, [apiUrl]);\n\n const notConfigured = !client || !stripePublishableKey || !edxSessionUrl;\n\n // Exchange edX session for viax token on page load.\n const sessionQuery = useViaxSessionQuery(notConfigured ? null : edxSessionUrl!);\n const sessionReady = !!sessionQuery.data;\n\n useEffect(() => {\n if (sessionQuery.data && client) {\n client.setToken(sessionQuery.data.viaxToken);\n }\n }, [sessionQuery.data, client]);\n\n // Fetch billing plans, subscriber count, and optional course once the viax session is ready.\n const billingPlansQuery = useBillingPlansQuery(client, sessionReady);\n const activeSubscriptionsQuery = useActiveSubscriptionsQuery(client, sessionReady);\n const courseDetailQuery = useCourseDetailQuery(client, sessionReady, courseRunKey);\n\n // --- state ---\n const [showBanner, setShowBanner] = useState(true);\n const [cart, setCart] = useState<Cart | null>(null);\n const [stripe, setStripe] = useState<StripeLike | null>(null);\n const [stripeReady, setStripeReady] = useState(false);\n const [cardReady, setCardReady] = useState(false);\n const [error, setError] = useState('');\n const [cardError, setCardError] = useState('');\n const [billing, setBilling] = useState<BillingInfo>({\n firstName: '', lastName: '', city: '', zip: '', country: 'US', line1: '', state: '',\n });\n const [selectedCycle, setSelectedCycle] = useState<BillingCycle>('monthly');\n const [processingSubscription, setProcessingSubscription] = useState(false);\n\n useEffect(() => {\n if (sessionQuery.error) {\n setError(sessionQuery.error.message);\n }\n }, [sessionQuery.error]);\n\n const setField = useCallback(\n (field: keyof BillingInfo, value: string) => setBilling((p: BillingInfo) => ({ ...p, [field]: value })),\n [],\n );\n\n // --- refs ---\n // Stripe instances — written inside useEffect and mutations.\n const stripeInstanceRef = useRef<StripeLike | null>(null);\n const cardNumberElementRef = useRef<StripeElementLike | null>(null);\n const elementsRef = useRef<StripeElementsLike | null>(null);\n const elementsMountedRef = useRef(false);\n // DOM mount targets — passed as ref={} to the Stripe Element host divs.\n const numberMountRef = useRef<HTMLDivElement | null>(null);\n const expiryMountRef = useRef<HTMLDivElement | null>(null);\n const cvcMountRef = useRef<HTMLDivElement | null>(null);\n const mountedRef = useRef(true);\n const completedRef = useRef(false);\n const sessionRef = useRef<EdxSessionResult | null>(null);\n\n useEffect(() => {\n sessionRef.current = sessionQuery.data ?? null;\n }, [sessionQuery.data]);\n\n // Mirror state into refs so mutations can read current values without stale closures.\n const cartRef = useRef<Cart | null>(null);\n const billingRef = useRef<BillingInfo>(billing);\n useEffect(() => {\n cartRef.current = cart;\n }, [cart]);\n useEffect(() => {\n billingRef.current = billing;\n }, [billing]);\n useEffect(() => {\n stripeInstanceRef.current = stripe;\n }, [stripe]);\n\n // --- server state ---\n const statusQuery = useCartStatusQuery(client, cart?.biId ?? null);\n const status: Status | null = statusQuery.data?.status ?? null;\n const lastComment = statusQuery.data?.lastComment ?? '';\n\n // Phase is 'ready' until a cart exists, then driven by bpStatus.\n const phase: Phase = cart ? phaseFor(status, status === STATUS.IN_CART) : 'ready';\n const subscriptionIdQuery = useSubscriptionIdQuery(\n client, cart?.biId ?? null, status === STATUS.SUBSCRIPTION_CREATED,\n );\n\n // --- mutations ---\n const { placeOrder: placeMutation } = useCheckoutMutations({\n client,\n sessionRef,\n stripeRef: stripeInstanceRef,\n cardNumberElRef: cardNumberElementRef,\n billingRef,\n setError: (msg: string) => {\n setProcessingSubscription(false);\n setError(msg);\n },\n setCardError: (msg: string) => {\n setProcessingSubscription(false);\n setCardError(msg);\n },\n onCartCreated: (created: Cart) => {\n // Sync the ref immediately so any same-tick readers see the cart\n // before the setCart → useEffect mirror runs.\n cartRef.current = created;\n if (mountedRef.current) setCart(created);\n },\n });\n\n // --- load Stripe.js on mount ---\n useEffect(() => {\n mountedRef.current = true;\n if (!stripePublishableKey) return undefined;\n\n (async () => {\n try {\n const instance = await loadStripe(stripePublishableKey);\n if (mountedRef.current) {\n setStripe(instance);\n setStripeReady(true);\n }\n } catch (e: unknown) {\n if (mountedRef.current) setError((e as Error).message);\n }\n })();\n\n return () => {\n mountedRef.current = false;\n };\n }, [stripePublishableKey]);\n\n // --- mount Stripe Elements once Stripe is loaded ---\n useEffect(() => {\n if (!stripe) return;\n if (!numberMountRef.current || !expiryMountRef.current || !cvcMountRef.current) return;\n // Hard guard — never recreate elements once mounted, even if stripe reference changes.\n if (elementsMountedRef.current) return;\n elementsMountedRef.current = true;\n\n setCardReady(false);\n\n const elements = stripe.elements();\n elementsRef.current = elements;\n\n const number = elements.create('cardNumber', { ...STRIPE_ELEMENT_OPTS, showIcon: true });\n const expiry = elements.create('cardExpiry', STRIPE_ELEMENT_OPTS);\n const cvc = elements.create('cardCvc', STRIPE_ELEMENT_OPTS);\n\n number.mount(numberMountRef.current);\n expiry.mount(expiryMountRef.current);\n cvc.mount(cvcMountRef.current);\n\n number.on('ready', () => {\n if (mountedRef.current) setCardReady(true);\n });\n number.on('change', (e: { error?: { message?: string } }) => {\n if (mountedRef.current) setCardError(e.error?.message || '');\n });\n\n cardNumberElementRef.current = number;\n }, [stripe]);\n\n // --- on success ---\n useEffect(() => {\n if (status !== STATUS.SUBSCRIPTION_CREATED || completedRef.current) return;\n completedRef.current = true;\n if (onComplete) onComplete(subscriptionIdQuery.data?.biId ?? null);\n }, [status, subscriptionIdQuery.data, onComplete]);\n\n // --- actions ---\n const placeOrder = useCallback((consent: CheckoutConsent) => {\n setError('');\n setCardError('');\n if (phase === 'failed') setCart(null);\n setProcessingSubscription(true);\n placeMutation.mutate(consent);\n }, [placeMutation, phase]);\n\n // Turn off processingSubscription once we reach a terminal status.\n useEffect(() => {\n if (!status) return;\n const terminalStatuses: Status[] = [\n STATUS.SUBSCRIPTION_CREATED,\n STATUS.STRIPE_FAIL,\n STATUS.SANCTION_BLOCK,\n ];\n if (terminalStatuses.includes(status)) {\n setProcessingSubscription(false);\n }\n }, [status]);\n\n return {\n phase,\n status,\n statusLabel: (status && STATUS_LABELS[status]) || 'Processing your order…',\n stripeReady,\n cardReady,\n notConfigured,\n showBanner,\n dismissBanner: () => setShowBanner(false),\n error,\n clearError: () => setError(''),\n cardError,\n lastComment,\n subscriptionDetails: subscriptionIdQuery.data ?? null,\n billing,\n setField,\n numberMountRef,\n expiryMountRef,\n cvcMountRef,\n submitting: placeMutation.isPending,\n processingSubscription,\n placeOrder,\n billingPlans: billingPlansQuery.data?.plans ?? [],\n activeSubscriberCount: activeSubscriptionsQuery.data?.active ?? null,\n selectedCycle,\n setCycle: setSelectedCycle,\n sessionReady,\n userCountry,\n course: courseDetailQuery.data ?? null,\n };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ export interface UseCheckoutGateOptions {
2
+ edxSessionUrl?: string;
3
+ learnerDashboardUrl?: string;
4
+ }
5
+ export type GateStatus = 'loading' | 'blocked' | 'allowed' | 'error';
6
+ export interface UseCheckoutGateResult {
7
+ /** 'loading' while session/checks are in flight, 'blocked' if country not allowed, 'allowed' if clear, 'error' if session failed. */
8
+ gateStatus: GateStatus;
9
+ /** ISO 3166-1 alpha-2 country code — passed down to Checkout for the UK/CA checkbox. */
10
+ userCountry: string | null;
11
+ learnerDashboardUrl: string | undefined;
12
+ /** Message when gateStatus is 'error' (typically a failed edx-session exchange). */
13
+ errorMessage: string | null;
14
+ }
15
+ export declare function useCheckoutGate(options?: UseCheckoutGateOptions): UseCheckoutGateResult;
@@ -0,0 +1,39 @@
1
+ import { ALLOWED_CHECKOUT_COUNTRIES, GATE_CHECK_COUNTRY, } from '../../constants';
2
+ import { useViaxSessionQuery, useUserCountryQuery, } from './useCheckoutQueries';
3
+ export function useCheckoutGate(options = {}) {
4
+ var _a, _b, _c;
5
+ const { edxSessionUrl, learnerDashboardUrl, } = options;
6
+ const sessionQuery = useViaxSessionQuery(edxSessionUrl !== null && edxSessionUrl !== void 0 ? edxSessionUrl : null);
7
+ const sessionReady = !!sessionQuery.data;
8
+ const userCountryQuery = useUserCountryQuery(sessionReady && GATE_CHECK_COUNTRY ? (edxSessionUrl !== null && edxSessionUrl !== void 0 ? edxSessionUrl : null) : null, (_b = (_a = sessionQuery.data) === null || _a === void 0 ? void 0 : _a.username) !== null && _b !== void 0 ? _b : null);
9
+ const userCountry = (_c = userCountryQuery.data) !== null && _c !== void 0 ? _c : null;
10
+ // Use isLoading (isPending && isFetching), not isPending alone.
11
+ // In TanStack Query v5, disabled queries with no data stay isPending forever —
12
+ // e.g. country check when username is missing from the session response.
13
+ const loading = (!sessionReady && !sessionQuery.isError)
14
+ || (GATE_CHECK_COUNTRY && userCountryQuery.isLoading);
15
+ // GATE_CHECK_COUNTRY=false → treat all countries as allowed.
16
+ const isCountryAllowed = !GATE_CHECK_COUNTRY
17
+ || userCountry === null
18
+ || ALLOWED_CHECKOUT_COUNTRIES.includes(userCountry);
19
+ let gateStatus;
20
+ if (sessionQuery.isError) {
21
+ gateStatus = 'error';
22
+ }
23
+ else if (loading) {
24
+ gateStatus = 'loading';
25
+ }
26
+ else if (!isCountryAllowed) {
27
+ gateStatus = 'blocked';
28
+ }
29
+ else {
30
+ gateStatus = 'allowed';
31
+ }
32
+ const errorMessage = sessionQuery.isError
33
+ ? (sessionQuery.error instanceof Error
34
+ ? sessionQuery.error.message
35
+ : 'Failed to establish checkout session.')
36
+ : null;
37
+ return { gateStatus, userCountry, learnerDashboardUrl, errorMessage };
38
+ }
39
+ //# sourceMappingURL=useCheckoutGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCheckoutGate.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckoutGate.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAmB9B,MAAM,UAAU,eAAe,CAAC,UAAkC,EAAE;;IAClE,MAAM,EACJ,aAAa,EACb,mBAAmB,GACpB,GAAG,OAAO,CAAC;IAEZ,MAAM,YAAY,GAAG,mBAAmB,CAAC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,IAAI,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;IAEzC,MAAM,gBAAgB,GAAG,mBAAmB,CAC1C,YAAY,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EACnE,MAAA,MAAA,YAAY,CAAC,IAAI,0CAAE,QAAQ,mCAAI,IAAI,CACpC,CAAC;IAEF,MAAM,WAAW,GAAG,MAAA,gBAAgB,CAAC,IAAI,mCAAI,IAAI,CAAC;IAElD,gEAAgE;IAChE,+EAA+E;IAC/E,yEAAyE;IACzE,MAAM,OAAO,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;WACnD,CAAC,kBAAkB,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAExD,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,CAAC,kBAAkB;WACvC,WAAW,KAAK,IAAI;WACpB,0BAA0B,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAEtD,IAAI,UAAsB,CAAC;IAC3B,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QACzB,UAAU,GAAG,OAAO,CAAC;IACvB,CAAC;SAAM,IAAI,OAAO,EAAE,CAAC;QACnB,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;SAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC7B,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;IAED,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO;QACvC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,YAAY,KAAK;YAClC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO;YAC5B,CAAC,CAAC,uCAAuC,CAAC;QAC9C,CAAC,CAAC,IAAI,CAAC;IAET,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AACxE,CAAC","sourcesContent":["import {\n ALLOWED_CHECKOUT_COUNTRIES,\n GATE_CHECK_COUNTRY,\n} from '../../constants';\nimport {\n useViaxSessionQuery,\n useUserCountryQuery,\n} from './useCheckoutQueries';\n\nexport interface UseCheckoutGateOptions {\n edxSessionUrl?: string,\n learnerDashboardUrl?: string,\n}\n\nexport type GateStatus = 'loading' | 'blocked' | 'allowed' | 'error';\n\nexport interface UseCheckoutGateResult {\n /** 'loading' while session/checks are in flight, 'blocked' if country not allowed, 'allowed' if clear, 'error' if session failed. */\n gateStatus: GateStatus,\n /** ISO 3166-1 alpha-2 country code — passed down to Checkout for the UK/CA checkbox. */\n userCountry: string | null,\n learnerDashboardUrl: string | undefined,\n /** Message when gateStatus is 'error' (typically a failed edx-session exchange). */\n errorMessage: string | null,\n}\n\nexport function useCheckoutGate(options: UseCheckoutGateOptions = {}): UseCheckoutGateResult {\n const {\n edxSessionUrl,\n learnerDashboardUrl,\n } = options;\n\n const sessionQuery = useViaxSessionQuery(edxSessionUrl ?? null);\n const sessionReady = !!sessionQuery.data;\n\n const userCountryQuery = useUserCountryQuery(\n sessionReady && GATE_CHECK_COUNTRY ? (edxSessionUrl ?? null) : null,\n sessionQuery.data?.username ?? null,\n );\n\n const userCountry = userCountryQuery.data ?? null;\n\n // Use isLoading (isPending && isFetching), not isPending alone.\n // In TanStack Query v5, disabled queries with no data stay isPending forever —\n // e.g. country check when username is missing from the session response.\n const loading = (!sessionReady && !sessionQuery.isError)\n || (GATE_CHECK_COUNTRY && userCountryQuery.isLoading);\n\n // GATE_CHECK_COUNTRY=false → treat all countries as allowed.\n const isCountryAllowed = !GATE_CHECK_COUNTRY\n || userCountry === null\n || ALLOWED_CHECKOUT_COUNTRIES.includes(userCountry);\n\n let gateStatus: GateStatus;\n if (sessionQuery.isError) {\n gateStatus = 'error';\n } else if (loading) {\n gateStatus = 'loading';\n } else if (!isCountryAllowed) {\n gateStatus = 'blocked';\n } else {\n gateStatus = 'allowed';\n }\n\n const errorMessage = sessionQuery.isError\n ? (sessionQuery.error instanceof Error\n ? sessionQuery.error.message\n : 'Failed to establish checkout session.')\n : null;\n\n return { gateStatus, userCountry, learnerDashboardUrl, errorMessage };\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { RefObject } from 'react';
2
+ import type { EdxSessionResult } from '../../utils/provision';
3
+ import type { CheckoutClient, StripeLike, StripeElementLike, Cart, BillingInfo, CheckoutConsent } from '../../types';
4
+ export interface CheckoutMutationsCtx {
5
+ client: CheckoutClient | null;
6
+ sessionRef: RefObject<EdxSessionResult | null>;
7
+ stripeRef: RefObject<StripeLike | null>;
8
+ cardNumberElRef: RefObject<StripeElementLike | null>;
9
+ billingRef: RefObject<BillingInfo | null>;
10
+ setError: (msg: string) => void;
11
+ setCardError: (msg: string) => void;
12
+ onCartCreated: (cart: Cart) => void;
13
+ }
14
+ export declare function useCheckoutMutations(ctx: CheckoutMutationsCtx): {
15
+ placeOrder: import("@tanstack/react-query").UseMutationResult<Cart, Error, CheckoutConsent, unknown>;
16
+ };
@@ -0,0 +1,131 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ /**
11
+ * query/useCheckoutMutations.ts — write-side TanStack mutations.
12
+ *
13
+ * The placeOrder mutation drives the checkout sequence on button click.
14
+ * The viax token and customerUid are established on page load via
15
+ * GET /edx-session and passed in through sessionRef.
16
+ *
17
+ * 1. getSalableUid + getBillingPlans (parallel)
18
+ * 2. createTwouCart
19
+ * 3. stripe.createPaymentMethod → pm_xxx
20
+ * 4. updateTwouCartItem → billing address + pm_xxx
21
+ * 5. updateTwouCart → consent fields (SUBS-228)
22
+ * 6. startBusinessProcessableTransition('Sanction_Check')
23
+ */
24
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
25
+ import { STATUS } from '../../constants';
26
+ import { checkoutKeys } from './keys';
27
+ class CardValidationError extends Error {
28
+ }
29
+ function toCartAddress(b) {
30
+ return {
31
+ tFirstName: b.firstName,
32
+ tLastName: b.lastName,
33
+ upaLine1: b.line1,
34
+ upaCity: b.city,
35
+ upaPostcode: b.zip,
36
+ gadStateOrProvince: b.state,
37
+ gadCountry: { iso2Code: b.country },
38
+ };
39
+ }
40
+ function toStripeAddress(b) {
41
+ return {
42
+ line1: b.line1 || undefined,
43
+ city: b.city || undefined,
44
+ state: b.state || undefined,
45
+ postal_code: b.zip || undefined,
46
+ country: b.country || undefined,
47
+ };
48
+ }
49
+ export function useCheckoutMutations(ctx) {
50
+ const queryClient = useQueryClient();
51
+ const optimisticConfirm = (cartBiId) => {
52
+ queryClient.setQueryData(checkoutKeys.status(cartBiId), (old) => {
53
+ var _a, _b;
54
+ return ({
55
+ status: STATUS.CONFIRM,
56
+ stripeSubscriptionId: (_a = old === null || old === void 0 ? void 0 : old.stripeSubscriptionId) !== null && _a !== void 0 ? _a : null,
57
+ lastComment: (_b = old === null || old === void 0 ? void 0 : old.lastComment) !== null && _b !== void 0 ? _b : '',
58
+ });
59
+ });
60
+ queryClient.invalidateQueries({ queryKey: checkoutKeys.status(cartBiId) });
61
+ };
62
+ const placeOrder = useMutation({
63
+ mutationFn: (consent) => __awaiter(this, void 0, void 0, function* () {
64
+ var _a;
65
+ const { client, stripeRef, cardNumberElRef, billingRef } = ctx;
66
+ const stripe = stripeRef.current;
67
+ const card = cardNumberElRef.current;
68
+ if (!client || !stripe || !card)
69
+ throw new Error('Checkout is not ready yet.');
70
+ const billing = billingRef.current;
71
+ if (!billing)
72
+ throw new Error('Billing information is not available. Please refresh and try again.');
73
+ const session = ctx.sessionRef.current;
74
+ if (!session) {
75
+ throw new Error('Checkout session is not ready yet. Please wait a moment and try again.');
76
+ }
77
+ const { customerUid } = session;
78
+ // ── Step 1: Fetch salable(product) uid + billing plans in parallel ─────────────
79
+ const [productInfo, plansResult] = yield Promise.all([
80
+ client.getSalableUid('TWOU-SUB-PLAN-001'),
81
+ client.getBillingPlans(),
82
+ ]);
83
+ const salableUid = productInfo.uid;
84
+ const defaultPlan = (_a = plansResult.plans.find((p) => !p.isTemplate)) !== null && _a !== void 0 ? _a : plansResult.plans[0];
85
+ if (!defaultPlan)
86
+ throw new Error('No billing plans available.');
87
+ const billingPlanUid = defaultPlan.uid;
88
+ // ── Step 2: Create the cart ───────────────────────────────────────────
89
+ const createdCart = yield client.createCart({ customerUid, salableUid, billingPlanUid });
90
+ ctx.onCartCreated(createdCart);
91
+ // ── Step 3: Tokenize the card (browser → Stripe) ──────────────────────
92
+ const { paymentMethod, error } = yield stripe.createPaymentMethod({
93
+ type: 'card',
94
+ card,
95
+ billing_details: {
96
+ name: `${billing.firstName} ${billing.lastName}`.trim(),
97
+ address: toStripeAddress(billing),
98
+ },
99
+ });
100
+ if (error || !paymentMethod) {
101
+ throw new CardValidationError((error === null || error === void 0 ? void 0 : error.message) || 'There was a problem with your card.');
102
+ }
103
+ // ── Step 4: Attach billing address + payment method to cart item ──────
104
+ const { cartItemUid } = yield client.getCartItem(createdCart.biId);
105
+ yield client.updateCartItem({
106
+ cartItemUid,
107
+ billingAddress: toCartAddress(billing),
108
+ paymentMethodId: paymentMethod.id,
109
+ });
110
+ // ── Step 5: Persist auto-renewal consent on the TwouCart BI ───────────
111
+ yield client.updateCartConsent({
112
+ cartUid: createdCart.uid,
113
+ consent,
114
+ });
115
+ // ── Step 6: Fire the backend workflow ─────────────────────────────────
116
+ yield client.placeOrder(createdCart.uid);
117
+ return createdCart;
118
+ }),
119
+ onSuccess: (cart) => {
120
+ optimisticConfirm(cart.biId);
121
+ },
122
+ onError: (err) => {
123
+ if (err instanceof CardValidationError)
124
+ ctx.setCardError(err.message);
125
+ else
126
+ ctx.setError(err.message);
127
+ },
128
+ });
129
+ return { placeOrder };
130
+ }
131
+ //# sourceMappingURL=useCheckoutMutations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCheckoutMutations.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckoutMutations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * query/useCheckoutMutations.ts — write-side TanStack mutations.\n *\n * The placeOrder mutation drives the checkout sequence on button click.\n * The viax token and customerUid are established on page load via\n * GET /edx-session and passed in through sessionRef.\n *\n * 1. getSalableUid + getBillingPlans (parallel)\n * 2. createTwouCart\n * 3. stripe.createPaymentMethod → pm_xxx\n * 4. updateTwouCartItem → billing address + pm_xxx\n * 5. updateTwouCart → consent fields (SUBS-228)\n * 6. startBusinessProcessableTransition('Sanction_Check')\n */\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport type { RefObject } from 'react';\nimport { STATUS } from '../../constants';\nimport { checkoutKeys } from './keys';\nimport type { EdxSessionResult } from '../../utils/provision';\nimport type {\n CheckoutClient, StripeLike, StripeElementLike, Cart, BillingInfo,\n CartBillingAddress, CartStatusResult, CheckoutConsent,\n} from '../../types';\n\nclass CardValidationError extends Error {}\n\nfunction toCartAddress(b: BillingInfo): CartBillingAddress {\n return {\n tFirstName: b.firstName,\n tLastName: b.lastName,\n upaLine1: b.line1,\n upaCity: b.city,\n upaPostcode: b.zip,\n gadStateOrProvince: b.state,\n gadCountry: { iso2Code: b.country },\n };\n}\n\nfunction toStripeAddress(b: BillingInfo): Record<string, string | undefined> {\n return {\n line1: b.line1 || undefined,\n city: b.city || undefined,\n state: b.state || undefined,\n postal_code: b.zip || undefined,\n country: b.country || undefined,\n };\n}\n\nexport interface CheckoutMutationsCtx {\n client: CheckoutClient | null,\n sessionRef: RefObject<EdxSessionResult | null>,\n stripeRef: RefObject<StripeLike | null>,\n cardNumberElRef: RefObject<StripeElementLike | null>,\n billingRef: RefObject<BillingInfo | null>,\n setError: (msg: string) => void,\n setCardError: (msg: string) => void,\n onCartCreated: (cart: Cart) => void,\n}\n\nexport function useCheckoutMutations(ctx: CheckoutMutationsCtx) {\n const queryClient = useQueryClient();\n\n const optimisticConfirm = (cartBiId: string) => {\n queryClient.setQueryData<CartStatusResult>(checkoutKeys.status(cartBiId), (old) => ({\n status: STATUS.CONFIRM,\n stripeSubscriptionId: old?.stripeSubscriptionId ?? null,\n lastComment: old?.lastComment ?? '',\n }));\n queryClient.invalidateQueries({ queryKey: checkoutKeys.status(cartBiId) });\n };\n\n const placeOrder = useMutation<Cart, Error, CheckoutConsent>({\n mutationFn: async (consent) => {\n const { client, stripeRef, cardNumberElRef, billingRef } = ctx;\n const stripe = stripeRef.current;\n const card = cardNumberElRef.current;\n if (!client || !stripe || !card) throw new Error('Checkout is not ready yet.');\n\n const billing = billingRef.current;\n if (!billing) throw new Error('Billing information is not available. Please refresh and try again.');\n\n const session = ctx.sessionRef.current;\n if (!session) {\n throw new Error('Checkout session is not ready yet. Please wait a moment and try again.');\n }\n const { customerUid } = session;\n\n // ── Step 1: Fetch salable(product) uid + billing plans in parallel ─────────────\n const [productInfo, plansResult] = await Promise.all([\n client.getSalableUid('TWOU-SUB-PLAN-001'),\n client.getBillingPlans(),\n ]);\n const salableUid = productInfo.uid;\n const defaultPlan = plansResult.plans.find((p) => !p.isTemplate) ?? plansResult.plans[0];\n if (!defaultPlan) throw new Error('No billing plans available.');\n const billingPlanUid = defaultPlan.uid;\n\n // ── Step 2: Create the cart ───────────────────────────────────────────\n const createdCart = await client.createCart({ customerUid, salableUid, billingPlanUid });\n ctx.onCartCreated(createdCart);\n\n // ── Step 3: Tokenize the card (browser → Stripe) ──────────────────────\n const { paymentMethod, error } = await stripe.createPaymentMethod({\n type: 'card',\n card,\n billing_details: {\n name: `${billing.firstName} ${billing.lastName}`.trim(),\n address: toStripeAddress(billing),\n },\n });\n if (error || !paymentMethod) {\n throw new CardValidationError(error?.message || 'There was a problem with your card.');\n }\n\n // ── Step 4: Attach billing address + payment method to cart item ──────\n const { cartItemUid } = await client.getCartItem(createdCart.biId);\n await client.updateCartItem({\n cartItemUid,\n billingAddress: toCartAddress(billing),\n paymentMethodId: paymentMethod.id,\n });\n\n // ── Step 5: Persist auto-renewal consent on the TwouCart BI ───────────\n await client.updateCartConsent({\n cartUid: createdCart.uid,\n consent,\n });\n\n // ── Step 6: Fire the backend workflow ─────────────────────────────────\n await client.placeOrder(createdCart.uid);\n\n return createdCart;\n },\n onSuccess: (cart) => {\n optimisticConfirm(cart.biId);\n },\n onError: (err) => {\n if (err instanceof CardValidationError) ctx.setCardError(err.message);\n else ctx.setError(err.message);\n },\n });\n\n return { placeOrder };\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import type { CheckoutClient, CartStatusResult, BillingPlansResult, CourseDetail } from '../../types';
2
+ /** Exchange edX session cookies for a viax token on page load. */
3
+ export declare function useViaxSessionQuery(sessionUrl: string | null): import("@tanstack/react-query").UseQueryResult<import("../../utils/provision").EdxSessionResult, Error>;
4
+ /**
5
+ * Fetches billing plans after the viax session is established.
6
+ * Used to display prices in CartSummary before the user starts checkout.
7
+ */
8
+ export declare function useBillingPlansQuery(client: CheckoutClient | null, sessionReady: boolean): import("@tanstack/react-query").UseQueryResult<BillingPlansResult, Error>;
9
+ /**
10
+ * Fetches the live active subscriber count after the viax session is ready.
11
+ * Refreshes every 5 minutes so the number stays roughly current.
12
+ */
13
+ export declare function useActiveSubscriptionsQuery(client: CheckoutClient | null, sessionReady: boolean): import("@tanstack/react-query").UseQueryResult<{
14
+ active: number;
15
+ }, Error>;
16
+ /**
17
+ * Fetches the user's country from their edX account profile.
18
+ * Derives the LMS base URL from the session URL (same origin).
19
+ * Returns null if the fetch fails or the field is absent — checkout stays open in that case.
20
+ */
21
+ export declare function useUserCountryQuery(sessionUrl: string | null, username: string | null): import("@tanstack/react-query").UseQueryResult<string | null, Error>;
22
+ /** Polls the cart state machine every second; stops on terminal states. */
23
+ export declare function useCartStatusQuery(client: CheckoutClient | null, cartBiId: string | null): import("@tanstack/react-query").UseQueryResult<CartStatusResult, Error>;
24
+ /** Looks up the created subscription biId after success. */
25
+ export declare function useSubscriptionIdQuery(client: CheckoutClient | null, cartBiId: string | null, enabled: boolean): import("@tanstack/react-query").UseQueryResult<import("../../types").SubscriptionDetails | null, Error>;
26
+ /**
27
+ * Fetches course details when the user arrived via ?course_run_key=.
28
+ * Skipped entirely when no course key is present (standard checkout).
29
+ */
30
+ export declare function useCourseDetailQuery(client: CheckoutClient | null, sessionReady: boolean, courseRunKey: string | null): import("@tanstack/react-query").UseQueryResult<CourseDetail | null, Error>;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * query/useCheckoutQueries.ts — read-side TanStack Query hooks.
3
+ *
4
+ * useViaxSessionQuery runs on mount to exchange the edX session for a viax
5
+ * token. Billing plans and subscriber count wait until the session is ready.
6
+ */
7
+ import { useQuery } from '@tanstack/react-query';
8
+ import { isTerminalStatus } from '../../constants';
9
+ import { checkoutKeys } from './keys';
10
+ import { fetchEdxSession, fetchUserCountry } from '../../utils/provision';
11
+ /** Exchange edX session cookies for a viax token on page load. */
12
+ export function useViaxSessionQuery(sessionUrl) {
13
+ return useQuery({
14
+ queryKey: checkoutKeys.viaxSession(),
15
+ enabled: !!sessionUrl,
16
+ queryFn: () => fetchEdxSession(sessionUrl),
17
+ staleTime: 5 * 60 * 1000,
18
+ retry: 1,
19
+ });
20
+ }
21
+ /**
22
+ * Fetches billing plans after the viax session is established.
23
+ * Used to display prices in CartSummary before the user starts checkout.
24
+ */
25
+ export function useBillingPlansQuery(client, sessionReady) {
26
+ return useQuery({
27
+ queryKey: checkoutKeys.billingPlans(),
28
+ enabled: !!client && sessionReady,
29
+ queryFn: () => client.getBillingPlans(),
30
+ staleTime: Infinity,
31
+ retry: 2,
32
+ });
33
+ }
34
+ /**
35
+ * Fetches the live active subscriber count after the viax session is ready.
36
+ * Refreshes every 5 minutes so the number stays roughly current.
37
+ */
38
+ export function useActiveSubscriptionsQuery(client, sessionReady) {
39
+ return useQuery({
40
+ queryKey: ['checkout', 'activeSubscriptions'],
41
+ enabled: !!client && sessionReady,
42
+ queryFn: () => client.getActiveSubscriptions(),
43
+ staleTime: 5 * 60 * 1000, // 5 minutes
44
+ retry: 1,
45
+ });
46
+ }
47
+ /**
48
+ * Fetches the user's country from their edX account profile.
49
+ * Derives the LMS base URL from the session URL (same origin).
50
+ * Returns null if the fetch fails or the field is absent — checkout stays open in that case.
51
+ */
52
+ export function useUserCountryQuery(sessionUrl, username) {
53
+ return useQuery({
54
+ queryKey: ['checkout', 'userCountry', username],
55
+ enabled: !!sessionUrl && !!username,
56
+ queryFn: () => {
57
+ const lmsBaseUrl = new URL(sessionUrl).origin;
58
+ return fetchUserCountry(lmsBaseUrl, username);
59
+ },
60
+ staleTime: Infinity,
61
+ retry: 1,
62
+ });
63
+ }
64
+ /** Polls the cart state machine every second; stops on terminal states. */
65
+ export function useCartStatusQuery(client, cartBiId) {
66
+ return useQuery({
67
+ queryKey: checkoutKeys.status(cartBiId !== null && cartBiId !== void 0 ? cartBiId : 'none'),
68
+ enabled: !!client && !!cartBiId,
69
+ queryFn: () => client.getCartStatus(cartBiId),
70
+ refetchInterval: (query) => { var _a, _b; return isTerminalStatus((_b = (_a = query.state.data) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : null) ? false : 1000; },
71
+ refetchOnWindowFocus: false,
72
+ gcTime: 0,
73
+ });
74
+ }
75
+ /** Looks up the created subscription biId after success. */
76
+ export function useSubscriptionIdQuery(client, cartBiId, enabled) {
77
+ return useQuery({
78
+ queryKey: checkoutKeys.subscriptionId(cartBiId !== null && cartBiId !== void 0 ? cartBiId : 'none'),
79
+ enabled: enabled && !!client && !!cartBiId,
80
+ queryFn: () => client.findSubscriptionBiId(cartBiId),
81
+ staleTime: Infinity,
82
+ });
83
+ }
84
+ /**
85
+ * Fetches course details when the user arrived via ?course_run_key=.
86
+ * Skipped entirely when no course key is present (standard checkout).
87
+ */
88
+ export function useCourseDetailQuery(client, sessionReady, courseRunKey) {
89
+ return useQuery({
90
+ queryKey: checkoutKeys.courseDetail(courseRunKey !== null && courseRunKey !== void 0 ? courseRunKey : 'none'),
91
+ enabled: !!client && sessionReady && !!courseRunKey,
92
+ queryFn: () => client.getCourseDetail(courseRunKey),
93
+ staleTime: Infinity,
94
+ retry: 1,
95
+ });
96
+ }
97
+ //# sourceMappingURL=useCheckoutQueries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCheckoutQueries.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckoutQueries.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * query/useCheckoutQueries.ts — read-side TanStack Query hooks.\n *\n * useViaxSessionQuery runs on mount to exchange the edX session for a viax\n * token. Billing plans and subscriber count wait until the session is ready.\n */\nimport { useQuery } from '@tanstack/react-query';\nimport { isTerminalStatus } from '../../constants';\nimport { checkoutKeys } from './keys';\nimport { fetchEdxSession, fetchUserCountry } from '../../utils/provision';\nimport type { CheckoutClient, CartStatusResult, BillingPlansResult, CourseDetail } from '../../types';\n\n/** Exchange edX session cookies for a viax token on page load. */\nexport function useViaxSessionQuery(sessionUrl: string | null) {\n return useQuery({\n queryKey: checkoutKeys.viaxSession(),\n enabled: !!sessionUrl,\n queryFn: () => fetchEdxSession(sessionUrl!),\n staleTime: 5 * 60 * 1000,\n retry: 1,\n });\n}\n\n/**\n * Fetches billing plans after the viax session is established.\n * Used to display prices in CartSummary before the user starts checkout.\n */\nexport function useBillingPlansQuery(client: CheckoutClient | null, sessionReady: boolean) {\n return useQuery({\n queryKey: checkoutKeys.billingPlans(),\n enabled: !!client && sessionReady,\n queryFn: (): Promise<BillingPlansResult> => client!.getBillingPlans(),\n staleTime: Infinity,\n retry: 2,\n });\n}\n\n/**\n * Fetches the live active subscriber count after the viax session is ready.\n * Refreshes every 5 minutes so the number stays roughly current.\n */\nexport function useActiveSubscriptionsQuery(client: CheckoutClient | null, sessionReady: boolean) {\n return useQuery({\n queryKey: ['checkout', 'activeSubscriptions'],\n enabled: !!client && sessionReady,\n queryFn: () => client!.getActiveSubscriptions(),\n staleTime: 5 * 60 * 1000, // 5 minutes\n retry: 1,\n });\n}\n\n/**\n * Fetches the user's country from their edX account profile.\n * Derives the LMS base URL from the session URL (same origin).\n * Returns null if the fetch fails or the field is absent — checkout stays open in that case.\n */\nexport function useUserCountryQuery(sessionUrl: string | null, username: string | null) {\n return useQuery({\n queryKey: ['checkout', 'userCountry', username],\n enabled: !!sessionUrl && !!username,\n queryFn: () => {\n const lmsBaseUrl = new URL(sessionUrl!).origin;\n return fetchUserCountry(lmsBaseUrl, username!);\n },\n staleTime: Infinity,\n retry: 1,\n });\n}\n\n/** Polls the cart state machine every second; stops on terminal states. */\nexport function useCartStatusQuery(client: CheckoutClient | null, cartBiId: string | null) {\n return useQuery({\n queryKey: checkoutKeys.status(cartBiId ?? 'none'),\n enabled: !!client && !!cartBiId,\n queryFn: (): Promise<CartStatusResult> => client!.getCartStatus(cartBiId!),\n refetchInterval: (query) =>\n isTerminalStatus(query.state.data?.status ?? null) ? false : 1000,\n refetchOnWindowFocus: false,\n gcTime: 0,\n });\n}\n\n/** Looks up the created subscription biId after success. */\nexport function useSubscriptionIdQuery(\n client: CheckoutClient | null,\n cartBiId: string | null,\n enabled: boolean,\n) {\n return useQuery({\n queryKey: checkoutKeys.subscriptionId(cartBiId ?? 'none'),\n enabled: enabled && !!client && !!cartBiId,\n queryFn: () => client!.findSubscriptionBiId(cartBiId!),\n staleTime: Infinity,\n });\n}\n\n/**\n * Fetches course details when the user arrived via ?course_run_key=.\n * Skipped entirely when no course key is present (standard checkout).\n */\nexport function useCourseDetailQuery(\n client: CheckoutClient | null,\n sessionReady: boolean,\n courseRunKey: string | null,\n) {\n return useQuery({\n queryKey: checkoutKeys.courseDetail(courseRunKey ?? 'none'),\n enabled: !!client && sessionReady && !!courseRunKey,\n queryFn: (): Promise<CourseDetail | null> => client!.getCourseDetail(courseRunKey!),\n staleTime: Infinity,\n retry: 1,\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export function getApiUrl(): string;
2
+ export function getSubsInitApiUrl(): string;
@@ -0,0 +1,4 @@
1
+ import { getSiteConfig } from '@openedx/frontend-base';
2
+ export const getApiUrl = () => (`${getSiteConfig().lmsBaseUrl}/api`);
3
+ export const getSubsInitApiUrl = () => (`${getApiUrl()}/subscription/init/`);
4
+ //# sourceMappingURL=urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urls.js","sourceRoot":"","sources":["../../../../src/data/services/subs/urls.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,aAAa,EAAE,CAAC,UAAU,MAAM,CAAC,CAAC;AAErE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,SAAS,EAAE,qBAAqB,CAAC,CAAC","sourcesContent":["import { getSiteConfig } from '@openedx/frontend-base';\n\nexport const getApiUrl = () => (`${getSiteConfig().lmsBaseUrl}/api`);\n\nexport const getSubsInitApiUrl = () => (`${getApiUrl()}/subscription/init/`);\n"]}
@@ -0,0 +1 @@
1
+ export { default } from './messages';
@@ -0,0 +1,2 @@
1
+ export { default } from './messages';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { default } from './messages';\n"]}
@@ -0,0 +1,2 @@
1
+ export { default as subscriptionCheckoutApp } from './app';
2
+ export { default as subscriptionCheckoutRoutes } from './routes';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as subscriptionCheckoutApp } from './app';
2
+ export { default as subscriptionCheckoutRoutes } from './routes';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { default as subscriptionCheckoutApp } from './app';\nexport { default as subscriptionCheckoutRoutes } from './routes';\n"]}
@@ -0,0 +1,8 @@
1
+ declare const messages: {
2
+ 'template.page.title': {
3
+ id: string;
4
+ defaultMessage: string;
5
+ description: string;
6
+ };
7
+ };
8
+ export default messages;
@@ -0,0 +1,10 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+ const messages = defineMessages({
3
+ 'template.page.title': {
4
+ id: 'template.page.title',
5
+ defaultMessage: 'Template | {siteName}',
6
+ description: 'Document title for the template app',
7
+ },
8
+ });
9
+ export default messages;
10
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,qBAAqB,EAAE;QACrB,EAAE,EAAE,qBAAqB;QACzB,cAAc,EAAE,uBAAuB;QACvC,WAAW,EAAE,qCAAqC;KACnD;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n 'template.page.title': {\n id: 'template.page.title',\n defaultMessage: 'Template | {siteName}',\n description: 'Document title for the template app',\n },\n});\n\nexport default messages;\n"]}
@@ -0,0 +1,18 @@
1
+ declare const routes: {
2
+ id: string;
3
+ path: string;
4
+ loader: (args: any) => Promise<null>;
5
+ handle: {
6
+ roles: string[];
7
+ };
8
+ lazy(): Promise<{
9
+ Component: () => import("react/jsx-runtime").JSX.Element;
10
+ }>;
11
+ children: {
12
+ index: boolean;
13
+ lazy(): Promise<{
14
+ Component: import("react").FC<{}>;
15
+ }>;
16
+ }[];
17
+ }[];
18
+ export default routes;
package/dist/routes.js ADDED
@@ -0,0 +1,67 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { authenticatedLoader, getAuthenticatedHttpClient, } from '@openedx/frontend-base';
11
+ import { redirect } from 'react-router-dom';
12
+ import { getSubsInitApiUrl } from './data/services/subs/urls';
13
+ import { subscriptionCheckoutRole } from './constants';
14
+ // loader to check if the user has subscription access
15
+ const subscriptionAccessLoader = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ try {
17
+ const { data } = yield getAuthenticatedHttpClient().get(getSubsInitApiUrl());
18
+ if (data.userSubscription && data.userSubscription.isSubscriber) {
19
+ throw redirect('/subscription-learner-dashboard'); // redirect to subscription learner dashboard if user have subscription access
20
+ }
21
+ return null;
22
+ }
23
+ catch (error) {
24
+ // Let redirect responses bubble up
25
+ if (error instanceof Response) {
26
+ throw error;
27
+ }
28
+ throw redirect('/learner-dashboard'); // redirect to learner dashboard if an error occurs
29
+ }
30
+ });
31
+ // composed loader that checks for authentication and subscription access
32
+ const protectedLoader = (args) => __awaiter(void 0, void 0, void 0, function* () {
33
+ yield authenticatedLoader(args);
34
+ yield subscriptionAccessLoader();
35
+ return null;
36
+ });
37
+ const routes = [
38
+ {
39
+ id: 'org.openedx.frontend.route.template.main',
40
+ path: 'checkout-page',
41
+ loader: protectedLoader,
42
+ handle: {
43
+ roles: [subscriptionCheckoutRole],
44
+ },
45
+ lazy() {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ const module = yield import(
48
+ /* webpackChunkName: "template-main" */ './Main');
49
+ return { Component: module.default };
50
+ });
51
+ },
52
+ children: [
53
+ {
54
+ index: true,
55
+ lazy() {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ const module = yield import(
58
+ /* webpackChunkName: "CheckoutPage" */ './checkoutPage/CheckoutPage');
59
+ return { Component: module.default };
60
+ });
61
+ },
62
+ },
63
+ ],
64
+ },
65
+ ];
66
+ export default routes;
67
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.tsx"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EACL,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,sDAAsD;AACtD,MAAM,wBAAwB,GAAG,GAAS,EAAE;IAC1C,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GACV,MAAM,0BAA0B,EAAE,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAEhE,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;YAChE,MAAM,QAAQ,CAAC,iCAAiC,CAAC,CAAC,CAAC,8EAA8E;QACnI,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mCAAmC;QACnC,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,mDAAmD;IAC3F,CAAC;AACH,CAAC,CAAA,CAAC;AAEF,yEAAyE;AACzE,MAAM,eAAe,GAAG,CAAO,IAAI,EAAE,EAAE;IACrC,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,wBAAwB,EAAE,CAAC;IAEjC,OAAO,IAAI,CAAC;AACd,CAAC,CAAA,CAAC;AAEF,MAAM,MAAM,GAAG;IACb;QACE,EAAE,EAAE,0CAA0C;QAC9C,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,eAAe;QACvB,MAAM,EAAE;YACN,KAAK,EAAE,CAAC,wBAAwB,CAAC;SAClC;QACK,IAAI;;gBACR,MAAM,MAAM,GAAG,MAAM,MAAM;gBACzB,uCAAuC,CAAC,QAAQ,CACjD,CAAC;gBACF,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;YACvC,CAAC;SAAA;QACD,QAAQ,EAAE;YACR;gBACE,KAAK,EAAE,IAAI;gBACL,IAAI;;wBACR,MAAM,MAAM,GAAG,MAAM,MAAM;wBACzB,sCAAsC,CAAC,6BAA6B,CACrE,CAAC;wBACF,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;oBACvC,CAAC;iBAAA;aACF;SACF;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC","sourcesContent":["import {\n authenticatedLoader,\n getAuthenticatedHttpClient,\n} from '@openedx/frontend-base';\nimport { redirect } from 'react-router-dom';\n\nimport { getSubsInitApiUrl } from './data/services/subs/urls';\nimport { subscriptionCheckoutRole } from './constants';\n\n// loader to check if the user has subscription access\nconst subscriptionAccessLoader = async () => {\n try {\n const { data }\n = await getAuthenticatedHttpClient().get(getSubsInitApiUrl());\n\n if (data.userSubscription && data.userSubscription.isSubscriber) {\n throw redirect('/subscription-learner-dashboard'); // redirect to subscription learner dashboard if user have subscription access\n }\n\n return null;\n } catch (error) {\n // Let redirect responses bubble up\n if (error instanceof Response) {\n throw error;\n }\n\n throw redirect('/learner-dashboard'); // redirect to learner dashboard if an error occurs\n }\n};\n\n// composed loader that checks for authentication and subscription access\nconst protectedLoader = async (args) => {\n await authenticatedLoader(args);\n await subscriptionAccessLoader();\n\n return null;\n};\n\nconst routes = [\n {\n id: 'org.openedx.frontend.route.template.main',\n path: 'checkout-page',\n loader: protectedLoader,\n handle: {\n roles: [subscriptionCheckoutRole],\n },\n async lazy() {\n const module = await import(\n /* webpackChunkName: \"template-main\" */ './Main'\n );\n return { Component: module.default };\n },\n children: [\n {\n index: true,\n async lazy() {\n const module = await import(\n /* webpackChunkName: \"CheckoutPage\" */ './checkoutPage/CheckoutPage'\n );\n return { Component: module.default };\n },\n },\n ],\n },\n];\n\nexport default routes;\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const exampleSlotId = "org.openedx.frontend.slot.template.example.v1";
2
+ declare const ExampleSlot: () => import("react/jsx-runtime").JSX.Element;
3
+ export default ExampleSlot;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Slot } from '@openedx/frontend-base';
3
+ export const exampleSlotId = 'org.openedx.frontend.slot.template.example.v1';
4
+ const ExampleSlot = () => (_jsx(Slot, { id: exampleSlotId }));
5
+ export default ExampleSlot;
6
+ //# sourceMappingURL=ExampleSlot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExampleSlot.js","sourceRoot":"","sources":["../../../src/slots/ExampleSlot/ExampleSlot.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,MAAM,CAAC,MAAM,aAAa,GAAG,+CAA+C,CAAC;AAE7E,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CACxB,KAAC,IAAI,IAAC,EAAE,EAAE,aAAa,GAAI,CAC5B,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { Slot } from '@openedx/frontend-base';\n\nexport const exampleSlotId = 'org.openedx.frontend.slot.template.example.v1';\n\nconst ExampleSlot = () => (\n <Slot id={exampleSlotId} />\n);\n\nexport default ExampleSlot;\n"]}
@@ -0,0 +1,3 @@
1
+ import { SlotOperation } from '@openedx/frontend-base';
2
+ declare const slots: SlotOperation[];
3
+ export default slots;