@edx/frontend-app-subscription-checkout 1.16.1 → 1.16.2

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.
@@ -20,8 +20,8 @@ import EnrollmentSummary from '../EnrollmentSummary/EnrollmentSummary';
20
20
  import PaymentForm from '../PaymentForm/PaymentForm';
21
21
  import CountryUnavailableModal from '../CountryUnavailableModal/CountryUnavailableModal';
22
22
  import { getPlanPrice, getRenewalLabel } from '../../utils/billingDetails';
23
- import { getTrialDateRange } from '../../utils';
24
23
  import { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';
24
+ import { getTrialDateRange } from '../../utils';
25
25
  import { SuccessScreen, BlockedScreen, ProcessingScreen } from '../StatusScreens/StatusScreens';
26
26
  import messages from './Messages';
27
27
  /** Resolve purchased cycle from subscription details, falling back to checkout selection. */
@@ -74,7 +74,9 @@ const Checkout = (_a) => {
74
74
  return _jsx(ProcessingScreen, {});
75
75
  }
76
76
  return (_jsxs(Row, { className: "checkout__container bg-light-200", children: [_jsx(CountryUnavailableModal, { isOpen: isBillingCountryBlocked, homeUrl: homeUrl }), _jsx(Col, { xs: 12, className: "d-lg-none", children: _jsx("h1", { className: "font-weight-bold text-primary-900", children: "Checkout" }) }), _jsx(Col, { xs: 12, children: _jsxs(Row, { className: "flex-column-reverse gap-5 flex-lg-row", children: [_jsx(Col, { xs: 12, lg: 7, xxl: 9, className: "payment__options", children: _jsxs("div", { children: [_jsx("h1", { className: "font-weight-bold text-primary-900 d-none d-lg-block", children: "Checkout" }), c.error && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: c.clearError, children: c.error })), showForm && (_jsxs(_Fragment, { children: [c.phase === 'failed' && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", children: failedMessage
77
- || formatMessage(messages.paymentProcessingDescription) })), _jsx(PaymentForm, { billing: c.billing, setField: c.setField, numberMountRef: c.numberMountRef, expiryMountRef: c.expiryMountRef, cvcMountRef: c.cvcMountRef, cardError: c.cardError, stripeReady: c.stripeReady, sessionReady: c.sessionReady, submitting: c.processingSubscription, onPlaceOrder: c.placeOrder, trialEnd: selectedCycle === 'monthly' ? displayEnd : undefined, priceToShow: selectedCycle === 'monthly' ? monthlyPrice : annualPrice, cycleToShow: selectedCycle === 'monthly' ? 'monthly' : 'annual', userCountry: c.userCountry, geolocationUrl: props.geolocationUrl, monthlyRegularAmount: monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.amount })] })), c.phase === 'success' && (_jsx(SuccessScreen, { subscriptionBiId: ((_d = c.subscriptionDetails) === null || _d === void 0 ? void 0 : _d.biId) || '', cardLast4: ((_e = c.subscriptionDetails) === null || _e === void 0 ? void 0 : _e.cardLast4) || '', purchaseDate: displayStart, trialStart: purchasedCycle === 'monthly' ? displayStart : undefined, trialEnd: purchasedCycle === 'monthly' ? displayEnd : undefined, priceToShow: purchasedCycle === 'monthly'
77
+ || (c.returningFromStripe
78
+ ? formatMessage(messages.paymentVerificationFailed)
79
+ : formatMessage(messages.paymentFailed)) })), _jsx(PaymentForm, { billing: c.billing, setField: c.setField, numberMountRef: c.numberMountRef, expiryMountRef: c.expiryMountRef, cvcMountRef: c.cvcMountRef, cardError: c.cardError, stripeReady: c.stripeReady, sessionReady: c.sessionReady, submitting: c.processingSubscription, onPlaceOrder: c.placeOrder, trialEnd: selectedCycle === 'monthly' ? displayEnd : undefined, priceToShow: selectedCycle === 'monthly' ? monthlyPrice : annualPrice, cycleToShow: selectedCycle === 'monthly' ? 'monthly' : 'annual', userCountry: c.userCountry, geolocationUrl: props.geolocationUrl, monthlyRegularAmount: monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.amount })] })), c.phase === 'success' && (_jsx(SuccessScreen, { subscriptionBiId: ((_d = c.subscriptionDetails) === null || _d === void 0 ? void 0 : _d.biId) || '', cardLast4: ((_e = c.subscriptionDetails) === null || _e === void 0 ? void 0 : _e.cardLast4) || '', purchaseDate: displayStart, trialStart: purchasedCycle === 'monthly' ? displayStart : undefined, trialEnd: purchasedCycle === 'monthly' ? displayEnd : undefined, priceToShow: purchasedCycle === 'monthly'
78
80
  ? monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.label
79
81
  : annualPrice === null || annualPrice === void 0 ? void 0 : annualPrice.label, cycleToShow: purchasedCycle === 'monthly' ? 'monthly' : 'annual', courseLabel: courseLabel, onFindCourse: handleStartCourse })), c.phase === 'blocked' && (_jsx(BlockedScreen, { detail: c.lastComment }))] }) }), _jsx(Col, { xs: 12, lg: 5, xxl: 3, className: "payment__summary", children: c.phase === 'success' ? (_jsx(EnrollmentSummary, { amount: purchasedPrice === null || purchasedPrice === void 0 ? void 0 : purchasedPrice.amount, monthlyRegularAmount: monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.amount, currency: purchasedPrice === null || purchasedPrice === void 0 ? void 0 : purchasedPrice.currency, cycleToShow: purchasedCycle, course: c.course, onStartCourse: handleStartCourse })) : (_jsx(CartSummary, { monthlyRegularAmount: monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.amount, annualAmount: annualPrice === null || annualPrice === void 0 ? void 0 : annualPrice.amount, currency: (_f = monthlyPrice === null || monthlyPrice === void 0 ? void 0 : monthlyPrice.currency) !== null && _f !== void 0 ? _f : annualPrice === null || annualPrice === void 0 ? void 0 : annualPrice.currency, monthlyRenewalLabel: getRenewalLabel(c.billingPlans, 'monthly'), annualRenewalLabel: getRenewalLabel(c.billingPlans, 'annual'), activeSubscriberCount: c.activeSubscriberCount, defaultCycle: selectedCycle, onCycleChange: c.processingSubscription ? undefined : c.setCycle, course: c.course })) })] }) })] }));
80
82
  };
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../../../src/components/Checkout/Checkout.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Alert, Col, Row } from '@openedx/paragon';\nimport { Error as ErrorIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport useCheckout from '../../data/hooks/useCheckout';\nimport type { UseCheckoutOptions } from '../../data/hooks/useCheckout';\nimport { ALLOWED_CHECKOUT_COUNTRIES, GATE_CHECK_COUNTRY } from '../../constants';\nimport CartSummary from '../CartSummary/CartSummary';\nimport EnrollmentSummary from '../EnrollmentSummary/EnrollmentSummary';\nimport PaymentForm from '../PaymentForm/PaymentForm';\nimport CountryUnavailableModal from '../CountryUnavailableModal/CountryUnavailableModal';\nimport { getPlanPrice, getRenewalLabel } from '../../utils/billingDetails';\nimport { getTrialDateRange } from '@src/utils';\nimport { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';\nimport { SuccessScreen, BlockedScreen, ProcessingScreen } from '../StatusScreens/StatusScreens';\nimport type { BillingCycle } from '../../types';\nimport messages from './Messages';\n\n/** Resolve purchased cycle from subscription details, falling back to checkout selection. */\nfunction resolvePurchasedCycle(\n selectedCycle: BillingCycle,\n planName?: string | null,\n renewalType?: string | null,\n): BillingCycle {\n const haystack = `${planName ?? ''} ${renewalType ?? ''}`.toLowerCase();\n if (haystack.includes('annual') || haystack.includes('year')) return 'annual';\n if (haystack.includes('month')) return 'monthly';\n return selectedCycle;\n}\n\nexport type CheckoutProps = UseCheckoutOptions & {\n /** Homepage URL for the country-unavailable modal CTA. */\n homeUrl?: string,\n /** Endpoint used to look up the representative IP for a selected country. */\n geolocationUrl?: string,\n};\n\nconst Checkout = ({\n homeUrl = '/',\n ...props\n}: CheckoutProps) => {\n const { formatMessage } = useIntl();\n const c = useCheckout(props);\n\n const showProcessing\n = c.returningFromStripe\n && c.processingSubscription\n && c.phase !== 'success'\n && c.phase !== 'blocked'\n && c.phase !== 'failed';\n const showForm\n = !showProcessing\n && (c.phase === 'init'\n || c.phase === 'ready'\n || c.phase === 'failed'\n || c.phase === 'processing');\n const monthlyPrice = getPlanPrice(c.billingPlans, 'monthly');\n const annualPrice = getPlanPrice(c.billingPlans, 'annual');\n const failedMessage = getLearnerFacingCheckoutMessage(c.lastComment);\n\n const { displayStart, displayEnd } = getTrialDateRange();\n\n const isBillingCountryBlocked = GATE_CHECK_COUNTRY\n && !!c.billing.country\n && !ALLOWED_CHECKOUT_COUNTRIES.includes(c.billing.country);\n\n const selectedCycle: BillingCycle = c.selectedCycle;\n\n const purchasedCycle = resolvePurchasedCycle(\n selectedCycle,\n c.subscriptionDetails?.planName,\n c.subscriptionDetails?.renewalType,\n );\n const purchasedPrice = getPlanPrice(c.billingPlans, purchasedCycle);\n\n const handleStartCourse = () => {\n if (c.course?.tUrlCourse) {\n window.location.href = c.course.tUrlCourse;\n } else {\n window.location.href = '/subscription-search';\n }\n };\n\n const courseLabel = c.course\n ? [c.course.tBrandText, c.course.maName].filter(Boolean).join(': ')\n : null;\n\n if (showProcessing) {\n return <ProcessingScreen />;\n }\n\n return (\n <Row className=\"checkout__container bg-light-200\">\n <CountryUnavailableModal\n isOpen={isBillingCountryBlocked}\n homeUrl={homeUrl}\n />\n <Col xs={12} className=\"d-lg-none\">\n <h1 className=\"font-weight-bold text-primary-900\">Checkout</h1>\n </Col>\n <Col xs={12}>\n <Row className=\"flex-column-reverse gap-5 flex-lg-row\">\n {/* ── LEFT ── */}\n <Col xs={12} lg={7} xxl={9} className=\"payment__options\">\n <div>\n <h1 className=\"font-weight-bold text-primary-900 d-none d-lg-block\">\n Checkout\n </h1>\n {c.error && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={c.clearError}\n >\n {c.error}\n </Alert>\n )}\n\n {showForm && (\n <>\n {c.phase === 'failed' && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {failedMessage\n || formatMessage(messages.paymentProcessingDescription)}\n </Alert>\n )}\n <PaymentForm\n billing={c.billing}\n setField={c.setField}\n numberMountRef={c.numberMountRef}\n expiryMountRef={c.expiryMountRef}\n cvcMountRef={c.cvcMountRef}\n cardError={c.cardError}\n stripeReady={c.stripeReady}\n sessionReady={c.sessionReady}\n submitting={c.processingSubscription}\n onPlaceOrder={c.placeOrder}\n trialEnd={selectedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={\n selectedCycle === 'monthly' ? monthlyPrice : annualPrice\n }\n cycleToShow={\n selectedCycle === 'monthly' ? 'monthly' : 'annual'\n }\n userCountry={c.userCountry}\n geolocationUrl={props.geolocationUrl}\n monthlyRegularAmount={monthlyPrice?.amount}\n />\n </>\n )}\n\n {c.phase === 'success' && (\n <SuccessScreen\n subscriptionBiId={c.subscriptionDetails?.biId || ''}\n cardLast4={c.subscriptionDetails?.cardLast4 || ''}\n purchaseDate={displayStart}\n trialStart={purchasedCycle === 'monthly' ? displayStart : undefined}\n trialEnd={purchasedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={\n purchasedCycle === 'monthly'\n ? monthlyPrice?.label\n : annualPrice?.label\n }\n cycleToShow={\n purchasedCycle === 'monthly' ? 'monthly' : 'annual'\n }\n courseLabel={courseLabel}\n onFindCourse={handleStartCourse}\n />\n )}\n\n {c.phase === 'blocked' && (\n <BlockedScreen detail={c.lastComment} />\n )}\n </div>\n </Col>\n\n {/* ── RIGHT — swaps to EnrollmentSummary on success ── */}\n <Col xs={12} lg={5} xxl={3} className=\"payment__summary\">\n {c.phase === 'success' ? (\n <EnrollmentSummary\n amount={purchasedPrice?.amount}\n monthlyRegularAmount={monthlyPrice?.amount}\n currency={purchasedPrice?.currency}\n cycleToShow={purchasedCycle}\n course={c.course}\n onStartCourse={handleStartCourse}\n />\n ) : (\n <CartSummary\n monthlyRegularAmount={monthlyPrice?.amount}\n annualAmount={annualPrice?.amount}\n currency={monthlyPrice?.currency ?? annualPrice?.currency}\n monthlyRenewalLabel={getRenewalLabel(c.billingPlans, 'monthly')}\n annualRenewalLabel={getRenewalLabel(c.billingPlans, 'annual')}\n activeSubscriberCount={c.activeSubscriberCount}\n defaultCycle={selectedCycle}\n onCycleChange={c.processingSubscription ? undefined : c.setCycle}\n course={c.course}\n />\n )}\n </Col>\n </Row>\n </Col>\n </Row>\n );\n};\n\nexport default Checkout;\n"]}
1
+ {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../../../src/components/Checkout/Checkout.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Alert, Col, Row } from '@openedx/paragon';\nimport { Error as ErrorIcon } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport useCheckout from '../../data/hooks/useCheckout';\nimport type { UseCheckoutOptions } from '../../data/hooks/useCheckout';\nimport { ALLOWED_CHECKOUT_COUNTRIES, GATE_CHECK_COUNTRY } from '../../constants';\nimport CartSummary from '../CartSummary/CartSummary';\nimport EnrollmentSummary from '../EnrollmentSummary/EnrollmentSummary';\nimport PaymentForm from '../PaymentForm/PaymentForm';\nimport CountryUnavailableModal from '../CountryUnavailableModal/CountryUnavailableModal';\nimport { getPlanPrice, getRenewalLabel } from '../../utils/billingDetails';\nimport { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';\nimport { getTrialDateRange } from '@src/utils';\nimport { SuccessScreen, BlockedScreen, ProcessingScreen } from '../StatusScreens/StatusScreens';\nimport type { BillingCycle } from '../../types';\nimport messages from './Messages';\n\n/** Resolve purchased cycle from subscription details, falling back to checkout selection. */\nfunction resolvePurchasedCycle(\n selectedCycle: BillingCycle,\n planName?: string | null,\n renewalType?: string | null,\n): BillingCycle {\n const haystack = `${planName ?? ''} ${renewalType ?? ''}`.toLowerCase();\n if (haystack.includes('annual') || haystack.includes('year')) return 'annual';\n if (haystack.includes('month')) return 'monthly';\n return selectedCycle;\n}\n\nexport type CheckoutProps = UseCheckoutOptions & {\n /** Homepage URL for the country-unavailable modal CTA. */\n homeUrl?: string,\n /** Endpoint used to look up the representative IP for a selected country. */\n geolocationUrl?: string,\n};\n\nconst Checkout = ({\n homeUrl = '/',\n ...props\n}: CheckoutProps) => {\n const { formatMessage } = useIntl();\n const c = useCheckout(props);\n\n const showProcessing\n = c.returningFromStripe\n && c.processingSubscription\n && c.phase !== 'success'\n && c.phase !== 'blocked'\n && c.phase !== 'failed';\n const showForm\n = !showProcessing\n && (c.phase === 'init'\n || c.phase === 'ready'\n || c.phase === 'failed'\n || c.phase === 'processing');\n const monthlyPrice = getPlanPrice(c.billingPlans, 'monthly');\n const annualPrice = getPlanPrice(c.billingPlans, 'annual');\n const failedMessage = getLearnerFacingCheckoutMessage(c.lastComment);\n\n const { displayStart, displayEnd } = getTrialDateRange();\n\n const isBillingCountryBlocked = GATE_CHECK_COUNTRY\n && !!c.billing.country\n && !ALLOWED_CHECKOUT_COUNTRIES.includes(c.billing.country);\n\n const selectedCycle: BillingCycle = c.selectedCycle;\n\n const purchasedCycle = resolvePurchasedCycle(\n selectedCycle,\n c.subscriptionDetails?.planName,\n c.subscriptionDetails?.renewalType,\n );\n const purchasedPrice = getPlanPrice(c.billingPlans, purchasedCycle);\n\n const handleStartCourse = () => {\n if (c.course?.tUrlCourse) {\n window.location.href = c.course.tUrlCourse;\n } else {\n window.location.href = '/subscription-search';\n }\n };\n\n const courseLabel = c.course\n ? [c.course.tBrandText, c.course.maName].filter(Boolean).join(': ')\n : null;\n\n if (showProcessing) {\n return <ProcessingScreen />;\n }\n\n return (\n <Row className=\"checkout__container bg-light-200\">\n <CountryUnavailableModal\n isOpen={isBillingCountryBlocked}\n homeUrl={homeUrl}\n />\n <Col xs={12} className=\"d-lg-none\">\n <h1 className=\"font-weight-bold text-primary-900\">Checkout</h1>\n </Col>\n <Col xs={12}>\n <Row className=\"flex-column-reverse gap-5 flex-lg-row\">\n {/* ── LEFT ── */}\n <Col xs={12} lg={7} xxl={9} className=\"payment__options\">\n <div>\n <h1 className=\"font-weight-bold text-primary-900 d-none d-lg-block\">\n Checkout\n </h1>\n {c.error && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={c.clearError}\n >\n {c.error}\n </Alert>\n )}\n\n {showForm && (\n <>\n {c.phase === 'failed' && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {failedMessage\n || (c.returningFromStripe\n ? formatMessage(messages.paymentVerificationFailed)\n : formatMessage(messages.paymentFailed))}\n </Alert>\n )}\n <PaymentForm\n billing={c.billing}\n setField={c.setField}\n numberMountRef={c.numberMountRef}\n expiryMountRef={c.expiryMountRef}\n cvcMountRef={c.cvcMountRef}\n cardError={c.cardError}\n stripeReady={c.stripeReady}\n sessionReady={c.sessionReady}\n submitting={c.processingSubscription}\n onPlaceOrder={c.placeOrder}\n trialEnd={selectedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={\n selectedCycle === 'monthly' ? monthlyPrice : annualPrice\n }\n cycleToShow={\n selectedCycle === 'monthly' ? 'monthly' : 'annual'\n }\n userCountry={c.userCountry}\n geolocationUrl={props.geolocationUrl}\n monthlyRegularAmount={monthlyPrice?.amount}\n />\n </>\n )}\n\n {c.phase === 'success' && (\n <SuccessScreen\n subscriptionBiId={c.subscriptionDetails?.biId || ''}\n cardLast4={c.subscriptionDetails?.cardLast4 || ''}\n purchaseDate={displayStart}\n trialStart={purchasedCycle === 'monthly' ? displayStart : undefined}\n trialEnd={purchasedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={\n purchasedCycle === 'monthly'\n ? monthlyPrice?.label\n : annualPrice?.label\n }\n cycleToShow={\n purchasedCycle === 'monthly' ? 'monthly' : 'annual'\n }\n courseLabel={courseLabel}\n onFindCourse={handleStartCourse}\n />\n )}\n\n {c.phase === 'blocked' && (\n <BlockedScreen detail={c.lastComment} />\n )}\n </div>\n </Col>\n\n {/* ── RIGHT — swaps to EnrollmentSummary on success ── */}\n <Col xs={12} lg={5} xxl={3} className=\"payment__summary\">\n {c.phase === 'success' ? (\n <EnrollmentSummary\n amount={purchasedPrice?.amount}\n monthlyRegularAmount={monthlyPrice?.amount}\n currency={purchasedPrice?.currency}\n cycleToShow={purchasedCycle}\n course={c.course}\n onStartCourse={handleStartCourse}\n />\n ) : (\n <CartSummary\n monthlyRegularAmount={monthlyPrice?.amount}\n annualAmount={annualPrice?.amount}\n currency={monthlyPrice?.currency ?? annualPrice?.currency}\n monthlyRenewalLabel={getRenewalLabel(c.billingPlans, 'monthly')}\n annualRenewalLabel={getRenewalLabel(c.billingPlans, 'annual')}\n activeSubscriberCount={c.activeSubscriberCount}\n defaultCycle={selectedCycle}\n onCycleChange={c.processingSubscription ? undefined : c.setCycle}\n course={c.course}\n />\n )}\n </Col>\n </Row>\n </Col>\n </Row>\n );\n};\n\nexport default Checkout;\n"]}
@@ -4,5 +4,15 @@ declare const messages: {
4
4
  defaultMessage: string;
5
5
  description: string;
6
6
  };
7
+ paymentVerificationFailed: {
8
+ id: string;
9
+ defaultMessage: string;
10
+ description: string;
11
+ };
12
+ paymentFailed: {
13
+ id: string;
14
+ defaultMessage: string;
15
+ description: string;
16
+ };
7
17
  };
8
18
  export default messages;
@@ -5,6 +5,16 @@ const messages = defineMessages({
5
5
  defaultMessage: 'Your payment could not be processed. Please check your card details and try again.',
6
6
  description: 'Payment processing description',
7
7
  },
8
+ paymentVerificationFailed: {
9
+ id: 'checkout.paymentForm.paymentVerificationFailed',
10
+ defaultMessage: 'Payment verification failed. Your payment could not be verified. Please try again with valid card details or contact support.',
11
+ description: 'Error message when payment verification fails after returning from Stripe',
12
+ },
13
+ paymentFailed: {
14
+ id: 'checkout.paymentForm.paymentFailed',
15
+ defaultMessage: 'Payment failed. Your payment could not be processed. Please check your card details and try again.',
16
+ description: 'Error message when payment fails',
17
+ },
8
18
  });
9
19
  export default messages;
10
20
  //# sourceMappingURL=Messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/Checkout/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,4BAA4B,EAAE;QAC5B,EAAE,EAAE,mDAAmD;QACvD,cAAc,EAAE,oFAAoF;QACpG,WAAW,EAAE,gCAAgC;KAC9C;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n paymentProcessingDescription: {\n id: 'checkout.paymentForm.paymentProcessingdescription',\n defaultMessage: 'Your payment could not be processed. Please check your card details and try again.',\n description: 'Payment processing description',\n },\n});\n\nexport default messages;\n"]}
1
+ {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/Checkout/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,4BAA4B,EAAE;QAC5B,EAAE,EAAE,mDAAmD;QACvD,cAAc,EAAE,oFAAoF;QACpG,WAAW,EAAE,gCAAgC;KAC9C;IACD,yBAAyB,EAAE;QACzB,EAAE,EAAE,gDAAgD;QACpD,cAAc,EAAE,+HAA+H;QAC/I,WAAW,EAAE,2EAA2E;KACzF;IACD,aAAa,EAAE;QACb,EAAE,EAAE,oCAAoC;QACxC,cAAc,EAAE,oGAAoG;QACpH,WAAW,EAAE,kCAAkC;KAChD;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n paymentProcessingDescription: {\n id: 'checkout.paymentForm.paymentProcessingdescription',\n defaultMessage: 'Your payment could not be processed. Please check your card details and try again.',\n description: 'Payment processing description',\n },\n paymentVerificationFailed: {\n id: 'checkout.paymentForm.paymentVerificationFailed',\n defaultMessage: 'Payment verification failed. Your payment could not be verified. Please try again with valid card details or contact support.',\n description: 'Error message when payment verification fails after returning from Stripe',\n },\n paymentFailed: {\n id: 'checkout.paymentForm.paymentFailed',\n defaultMessage: 'Payment failed. Your payment could not be processed. Please check your card details and try again.',\n description: 'Error message when payment fails',\n },\n});\n\nexport default messages;\n"]}
@@ -154,9 +154,24 @@ export default function useCheckout(options = {}) {
154
154
  // from. The returned cart waits for the viax session so the status request
155
155
  // carries a valid token.
156
156
  const cartBiId = (_a = cart === null || cart === void 0 ? void 0 : cart.biId) !== null && _a !== void 0 ? _a : (sessionReady ? returnedCartBiId : null);
157
- const statusQuery = useCartStatusQuery(client, cartBiId);
157
+ const statusQuery = useCartStatusQuery(client, cartBiId, returnedCartBiId ? 3 : false);
158
158
  const status = (_c = (_b = statusQuery.data) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : null;
159
159
  const lastComment = (_e = (_d = statusQuery.data) === null || _d === void 0 ? void 0 : _d.lastComment) !== null && _e !== void 0 ? _e : '';
160
+ const { isSuccess: isStatusSuccess, refetch: refetchStatus } = statusQuery;
161
+ const postReturnRefetchBiIdRef = useRef(null);
162
+ // When returning from Stripe, immediately refetch status instead of waiting 1 second
163
+ // This ensures spinner hides and error message shows quickly
164
+ useEffect(() => {
165
+ if (!returnedCartBiId) {
166
+ postReturnRefetchBiIdRef.current = null;
167
+ return;
168
+ }
169
+ if (isStatusSuccess
170
+ && postReturnRefetchBiIdRef.current !== returnedCartBiId) {
171
+ postReturnRefetchBiIdRef.current = returnedCartBiId;
172
+ refetchStatus();
173
+ }
174
+ }, [isStatusSuccess, refetchStatus, returnedCartBiId]);
160
175
  // Phase is 'ready' until a cart exists, then driven by bpStatus.
161
176
  const phase = cartBiId ? phaseFor(status, status === STATUS.IN_CART) : 'ready';
162
177
  const subscriptionIdQuery = useSubscriptionIdQuery(client, cartBiId, status === STATUS.SUBSCRIPTION_CREATED);
@@ -270,11 +285,13 @@ export default function useCheckout(options = {}) {
270
285
  // navigation (not an API request) for either flow.
271
286
  useEffect(() => {
272
287
  var _a, _b;
273
- const redirectUrl = ((_a = statusQuery.data) === null || _a === void 0 ? void 0 : _a.stripeConfirmationRedirectUrl)
274
- || ((_b = statusQuery.data) === null || _b === void 0 ? void 0 : _b.paypalApprovalUrl);
288
+ const stripeRedirectUrl = (_a = statusQuery.data) === null || _a === void 0 ? void 0 : _a.stripeConfirmationRedirectUrl;
289
+ const paypalRedirectUrl = (_b = statusQuery.data) === null || _b === void 0 ? void 0 : _b.paypalApprovalUrl;
290
+ const redirectUrl = stripeRedirectUrl || paypalRedirectUrl;
275
291
  if (status !== STATUS.STRIPE_CONFIRMATION_REQUIRED
276
292
  || !redirectUrl
277
- || redirectedUrlRef.current === redirectUrl)
293
+ || redirectedUrlRef.current === redirectUrl
294
+ || (returnedCartBiId !== null && redirectUrl === stripeRedirectUrl))
278
295
  return;
279
296
  redirectedUrlRef.current = redirectUrl;
280
297
  redirectToUrl(redirectUrl);
@@ -283,6 +300,7 @@ export default function useCheckout(options = {}) {
283
300
  (_f = statusQuery.data) === null || _f === void 0 ? void 0 : _f.stripeConfirmationRedirectUrl,
284
301
  (_g = statusQuery.data) === null || _g === void 0 ? void 0 : _g.paypalApprovalUrl,
285
302
  redirectToUrl,
303
+ returnedCartBiId,
286
304
  ]);
287
305
  // --- actions ---
288
306
  const placeOrder = useCallback((consent, paymentMethod = 'card') => {
@@ -1 +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 { getPlanFromUrl, writePlanQueryParam } from '../../utils/planQuery';\nimport { getReturnedCartBiIdFromUrl, loadStripe } from '../../utils/stripe';\nimport {\n STATUS,\n STATUS_LABELS,\n STRIPE_ELEMENT_OPTS,\n phaseFor,\n DEFAULTS,\n BILLING_COUNTRIES,\n} from '../../constants';\nimport type {\n Status, Phase, Cart, BillingInfo, CheckoutClient, StripeLike, StripeElementLike,\n StripeElementsLike, BillingPlan, CheckoutConsent, SupportedPaymentMethod,\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\nconst redirectBrowser = (url: string): void => {\n window.location.assign(url);\n};\n\nconst getInitialBillingCountry = (userCountry: string | null): string => {\n const normalized = userCountry?.trim().toUpperCase();\n if (normalized && BILLING_COUNTRIES.some(([countryCode]) => countryCode === normalized)) {\n return normalized;\n }\n return 'US';\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 /** Override only for tests; production performs a full-page browser redirect. */\n redirectToUrl?: (url: string) => void,\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 /** True when Stripe sent the learner back with ?cart_bi_id=. */\n returningFromStripe: boolean,\n placeOrder: (consent: CheckoutConsent, paymentMethod?: SupportedPaymentMethod) => 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 redirectToUrl = redirectBrowser,\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: getInitialBillingCountry(userCountry), line1: '', state: '',\n });\n const [selectedCycle, setSelectedCycle] = useState<BillingCycle>(getPlanFromUrl);\n // Set when Stripe returns from a 3DS challenge; cleared once a new attempt starts.\n const [returnedCartBiId, setReturnedCartBiId] = useState<string | null>(getReturnedCartBiIdFromUrl);\n const [processingSubscription, setProcessingSubscription] = useState(\n () => getReturnedCartBiIdFromUrl() !== null,\n );\n\n const setCycle = useCallback((cycle: BillingCycle) => {\n setSelectedCycle(cycle);\n writePlanQueryParam(cycle);\n }, []);\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 cardExpiryElementRef = useRef<StripeElementLike | null>(null);\n const cardCvcElementRef = useRef<StripeElementLike | null>(null);\n const elementsRef = useRef<StripeElementsLike | null>(null);\n // DOM mount targets — callback refs so we remount when hosts leave and return.\n const numberMountNodeRef = useRef<HTMLDivElement | null>(null);\n const expiryMountNodeRef = useRef<HTMLDivElement | null>(null);\n const cvcMountNodeRef = useRef<HTMLDivElement | null>(null);\n const [cardHostsEpoch, setCardHostsEpoch] = useState(0);\n\n const assignCardHost = useCallback((\n store: { current: HTMLDivElement | null },\n node: HTMLDivElement | null,\n ) => {\n store.current = node;\n if (\n numberMountNodeRef.current\n && expiryMountNodeRef.current\n && cvcMountNodeRef.current\n ) {\n setCardHostsEpoch((n) => n + 1);\n return;\n }\n // Hosts are leaving the DOM — detach so Stripe is not bound to dead nodes.\n cardNumberElementRef.current?.unmount?.();\n cardExpiryElementRef.current?.unmount?.();\n cardCvcElementRef.current?.unmount?.();\n }, []);\n\n const numberMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(numberMountNodeRef, node);\n }, [assignCardHost]);\n const expiryMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(expiryMountNodeRef, node);\n }, [assignCardHost]);\n const cvcMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(cvcMountNodeRef, node);\n }, [assignCardHost]);\n const mountedRef = useRef(true);\n const completedRef = useRef(false);\n const redirectedUrlRef = useRef<string | null>(null);\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 const selectedCycleRef = useRef<BillingCycle>(selectedCycle);\n\n useEffect(() => {\n cartRef.current = cart;\n }, [cart]);\n useEffect(() => {\n billingRef.current = billing;\n }, [billing]);\n useEffect(() => {\n selectedCycleRef.current = selectedCycle;\n }, [selectedCycle]);\n useEffect(() => {\n stripeInstanceRef.current = stripe;\n }, [stripe]);\n\n // --- server state ---\n // Poll the cart created in this session, or the one Stripe just returned\n // from. The returned cart waits for the viax session so the status request\n // carries a valid token.\n const cartBiId = cart?.biId ?? (sessionReady ? returnedCartBiId : null);\n const statusQuery = useCartStatusQuery(client, cartBiId);\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 = cartBiId ? phaseFor(status, status === STATUS.IN_CART) : 'ready';\n const subscriptionIdQuery = useSubscriptionIdQuery(\n client, cartBiId, 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 selectedCycleRef,\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; remount if hosts return ---\n useEffect(() => {\n if (!stripe) return;\n const numberNode = numberMountNodeRef.current;\n const expiryNode = expiryMountNodeRef.current;\n const cvcNode = cvcMountNodeRef.current;\n if (!numberNode || !expiryNode || !cvcNode) return;\n\n if (cardNumberElementRef.current && cardExpiryElementRef.current && cardCvcElementRef.current) {\n try {\n cardNumberElementRef.current.unmount?.();\n cardExpiryElementRef.current.unmount?.();\n cardCvcElementRef.current.unmount?.();\n cardNumberElementRef.current.mount(numberNode);\n cardExpiryElementRef.current.mount(expiryNode);\n cardCvcElementRef.current.mount(cvcNode);\n return;\n } catch {\n // Element is bound to a destroyed host — create a fresh Elements group.\n cardNumberElementRef.current = null;\n cardExpiryElementRef.current = null;\n cardCvcElementRef.current = null;\n elementsRef.current = null;\n }\n }\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(numberNode);\n expiry.mount(expiryNode);\n cvc.mount(cvcNode);\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 cardExpiryElementRef.current = expiry;\n cardCvcElementRef.current = cvc;\n }, [stripe, cardHostsEpoch]);\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 // Stripe and PayPal both authenticate the buyer on a hosted page before\n // returning the browser to checkout, so this must be a full-page\n // navigation (not an API request) for either flow.\n useEffect(() => {\n const redirectUrl = statusQuery.data?.stripeConfirmationRedirectUrl\n || statusQuery.data?.paypalApprovalUrl;\n if (\n status !== STATUS.STRIPE_CONFIRMATION_REQUIRED\n || !redirectUrl\n || redirectedUrlRef.current === redirectUrl\n ) return;\n\n redirectedUrlRef.current = redirectUrl;\n redirectToUrl(redirectUrl);\n }, [\n status,\n statusQuery.data?.stripeConfirmationRedirectUrl,\n statusQuery.data?.paypalApprovalUrl,\n redirectToUrl,\n ]);\n\n // --- actions ---\n const placeOrder = useCallback((consent: CheckoutConsent, paymentMethod: SupportedPaymentMethod = 'card') => {\n setError('');\n setCardError('');\n if (phase === 'failed') setCart(null);\n // Each attempt creates its own cart, so stop reporting on the returned one.\n setReturnedCartBiId(null);\n setProcessingSubscription(true);\n placeMutation.mutate({ consent, paymentMethod });\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 returningFromStripe: returnedCartBiId !== null,\n placeOrder,\n billingPlans: billingPlansQuery.data?.plans ?? [],\n activeSubscriberCount: activeSubscriptionsQuery.data?.active ?? null,\n selectedCycle,\n setCycle,\n sessionReady,\n userCountry,\n course: courseDetailQuery.data ?? null,\n };\n}\n"]}
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 { getPlanFromUrl, writePlanQueryParam } from '../../utils/planQuery';\nimport { getReturnedCartBiIdFromUrl, loadStripe } from '../../utils/stripe';\nimport {\n STATUS,\n STATUS_LABELS,\n STRIPE_ELEMENT_OPTS,\n phaseFor,\n DEFAULTS,\n BILLING_COUNTRIES,\n} from '../../constants';\nimport type {\n Status, Phase, Cart, BillingInfo, CheckoutClient, StripeLike, StripeElementLike,\n StripeElementsLike, BillingPlan, CheckoutConsent, SupportedPaymentMethod,\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\nconst redirectBrowser = (url: string): void => {\n window.location.assign(url);\n};\n\nconst getInitialBillingCountry = (userCountry: string | null): string => {\n const normalized = userCountry?.trim().toUpperCase();\n if (normalized && BILLING_COUNTRIES.some(([countryCode]) => countryCode === normalized)) {\n return normalized;\n }\n return 'US';\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 /** Override only for tests; production performs a full-page browser redirect. */\n redirectToUrl?: (url: string) => void,\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 /** True when Stripe sent the learner back with ?cart_bi_id=. */\n returningFromStripe: boolean,\n placeOrder: (consent: CheckoutConsent, paymentMethod?: SupportedPaymentMethod) => 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 redirectToUrl = redirectBrowser,\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: getInitialBillingCountry(userCountry), line1: '', state: '',\n });\n const [selectedCycle, setSelectedCycle] = useState<BillingCycle>(getPlanFromUrl);\n // Set when Stripe returns from a 3DS challenge; cleared once a new attempt starts.\n const [returnedCartBiId, setReturnedCartBiId] = useState<string | null>(getReturnedCartBiIdFromUrl);\n const [processingSubscription, setProcessingSubscription] = useState(\n () => getReturnedCartBiIdFromUrl() !== null,\n );\n\n const setCycle = useCallback((cycle: BillingCycle) => {\n setSelectedCycle(cycle);\n writePlanQueryParam(cycle);\n }, []);\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 cardExpiryElementRef = useRef<StripeElementLike | null>(null);\n const cardCvcElementRef = useRef<StripeElementLike | null>(null);\n const elementsRef = useRef<StripeElementsLike | null>(null);\n // DOM mount targets — callback refs so we remount when hosts leave and return.\n const numberMountNodeRef = useRef<HTMLDivElement | null>(null);\n const expiryMountNodeRef = useRef<HTMLDivElement | null>(null);\n const cvcMountNodeRef = useRef<HTMLDivElement | null>(null);\n const [cardHostsEpoch, setCardHostsEpoch] = useState(0);\n\n const assignCardHost = useCallback((\n store: { current: HTMLDivElement | null },\n node: HTMLDivElement | null,\n ) => {\n store.current = node;\n if (\n numberMountNodeRef.current\n && expiryMountNodeRef.current\n && cvcMountNodeRef.current\n ) {\n setCardHostsEpoch((n) => n + 1);\n return;\n }\n // Hosts are leaving the DOM — detach so Stripe is not bound to dead nodes.\n cardNumberElementRef.current?.unmount?.();\n cardExpiryElementRef.current?.unmount?.();\n cardCvcElementRef.current?.unmount?.();\n }, []);\n\n const numberMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(numberMountNodeRef, node);\n }, [assignCardHost]);\n const expiryMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(expiryMountNodeRef, node);\n }, [assignCardHost]);\n const cvcMountRef = useCallback((node: HTMLDivElement | null) => {\n assignCardHost(cvcMountNodeRef, node);\n }, [assignCardHost]);\n const mountedRef = useRef(true);\n const completedRef = useRef(false);\n const redirectedUrlRef = useRef<string | null>(null);\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 const selectedCycleRef = useRef<BillingCycle>(selectedCycle);\n\n useEffect(() => {\n cartRef.current = cart;\n }, [cart]);\n useEffect(() => {\n billingRef.current = billing;\n }, [billing]);\n useEffect(() => {\n selectedCycleRef.current = selectedCycle;\n }, [selectedCycle]);\n useEffect(() => {\n stripeInstanceRef.current = stripe;\n }, [stripe]);\n\n // --- server state ---\n // Poll the cart created in this session, or the one Stripe just returned\n // from. The returned cart waits for the viax session so the status request\n // carries a valid token.\n const cartBiId = cart?.biId ?? (sessionReady ? returnedCartBiId : null);\n const statusQuery = useCartStatusQuery(client, cartBiId, returnedCartBiId ? 3 : false);\n const status: Status | null = statusQuery.data?.status ?? null;\n const lastComment = statusQuery.data?.lastComment ?? '';\n const { isSuccess: isStatusSuccess, refetch: refetchStatus } = statusQuery;\n const postReturnRefetchBiIdRef = useRef<string | null>(null);\n\n // When returning from Stripe, immediately refetch status instead of waiting 1 second\n // This ensures spinner hides and error message shows quickly\n useEffect(() => {\n if (!returnedCartBiId) {\n postReturnRefetchBiIdRef.current = null;\n return;\n }\n\n if (\n isStatusSuccess\n && postReturnRefetchBiIdRef.current !== returnedCartBiId\n ) {\n postReturnRefetchBiIdRef.current = returnedCartBiId;\n refetchStatus();\n }\n }, [isStatusSuccess, refetchStatus, returnedCartBiId]);\n\n // Phase is 'ready' until a cart exists, then driven by bpStatus.\n const phase: Phase = cartBiId ? phaseFor(status, status === STATUS.IN_CART) : 'ready';\n const subscriptionIdQuery = useSubscriptionIdQuery(\n client, cartBiId, 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 selectedCycleRef,\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; remount if hosts return ---\n useEffect(() => {\n if (!stripe) return;\n const numberNode = numberMountNodeRef.current;\n const expiryNode = expiryMountNodeRef.current;\n const cvcNode = cvcMountNodeRef.current;\n if (!numberNode || !expiryNode || !cvcNode) return;\n\n if (cardNumberElementRef.current && cardExpiryElementRef.current && cardCvcElementRef.current) {\n try {\n cardNumberElementRef.current.unmount?.();\n cardExpiryElementRef.current.unmount?.();\n cardCvcElementRef.current.unmount?.();\n cardNumberElementRef.current.mount(numberNode);\n cardExpiryElementRef.current.mount(expiryNode);\n cardCvcElementRef.current.mount(cvcNode);\n return;\n } catch {\n // Element is bound to a destroyed host — create a fresh Elements group.\n cardNumberElementRef.current = null;\n cardExpiryElementRef.current = null;\n cardCvcElementRef.current = null;\n elementsRef.current = null;\n }\n }\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(numberNode);\n expiry.mount(expiryNode);\n cvc.mount(cvcNode);\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 cardExpiryElementRef.current = expiry;\n cardCvcElementRef.current = cvc;\n }, [stripe, cardHostsEpoch]);\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 // Stripe and PayPal both authenticate the buyer on a hosted page before\n // returning the browser to checkout, so this must be a full-page\n // navigation (not an API request) for either flow.\n useEffect(() => {\n const stripeRedirectUrl = statusQuery.data?.stripeConfirmationRedirectUrl;\n const paypalRedirectUrl = statusQuery.data?.paypalApprovalUrl;\n const redirectUrl = stripeRedirectUrl || paypalRedirectUrl;\n if (\n status !== STATUS.STRIPE_CONFIRMATION_REQUIRED\n || !redirectUrl\n || redirectedUrlRef.current === redirectUrl\n || (returnedCartBiId !== null && redirectUrl === stripeRedirectUrl)\n ) return;\n\n redirectedUrlRef.current = redirectUrl;\n redirectToUrl(redirectUrl);\n }, [\n status,\n statusQuery.data?.stripeConfirmationRedirectUrl,\n statusQuery.data?.paypalApprovalUrl,\n redirectToUrl,\n returnedCartBiId,\n ]);\n\n // --- actions ---\n const placeOrder = useCallback((consent: CheckoutConsent, paymentMethod: SupportedPaymentMethod = 'card') => {\n setError('');\n setCardError('');\n if (phase === 'failed') setCart(null);\n // Each attempt creates its own cart, so stop reporting on the returned one.\n setReturnedCartBiId(null);\n setProcessingSubscription(true);\n placeMutation.mutate({ consent, paymentMethod });\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 returningFromStripe: returnedCartBiId !== null,\n placeOrder,\n billingPlans: billingPlansQuery.data?.plans ?? [],\n activeSubscriberCount: activeSubscriptionsQuery.data?.active ?? null,\n selectedCycle,\n setCycle,\n sessionReady,\n userCountry,\n course: courseDetailQuery.data ?? null,\n };\n}\n"]}
@@ -22,7 +22,7 @@ export declare function useCurrentUserSubscriberQuery(client: CheckoutClient | n
22
22
  */
23
23
  export declare function useUserCountryQuery(sessionUrl: string | null, username: string | null): import("@tanstack/react-query").UseQueryResult<string | null, Error>;
24
24
  /** Polls the cart state machine every second; stops on terminal states. */
25
- export declare function useCartStatusQuery(client: CheckoutClient | null, cartBiId: string | null): import("@tanstack/react-query").UseQueryResult<CartStatusResult, Error>;
25
+ export declare function useCartStatusQuery(client: CheckoutClient | null, cartBiId: string | null, retryOnFailure?: boolean | number): import("@tanstack/react-query").UseQueryResult<CartStatusResult, Error>;
26
26
  /** Looks up the created subscription biId after success. */
27
27
  export declare function useSubscriptionIdQuery(client: CheckoutClient | null, cartBiId: string | null, enabled: boolean): import("@tanstack/react-query").UseQueryResult<import("../../types").SubscriptionDetails | null, Error>;
28
28
  /**
@@ -72,7 +72,7 @@ export function useUserCountryQuery(sessionUrl, username) {
72
72
  });
73
73
  }
74
74
  /** Polls the cart state machine every second; stops on terminal states. */
75
- export function useCartStatusQuery(client, cartBiId) {
75
+ export function useCartStatusQuery(client, cartBiId, retryOnFailure = false) {
76
76
  return useQuery({
77
77
  queryKey: checkoutKeys.status(cartBiId !== null && cartBiId !== void 0 ? cartBiId : 'none'),
78
78
  enabled: !!client && !!cartBiId,
@@ -80,6 +80,10 @@ export function useCartStatusQuery(client, cartBiId) {
80
80
  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; },
81
81
  refetchOnWindowFocus: false,
82
82
  gcTime: 0,
83
+ retry: retryOnFailure,
84
+ retryDelay: retryOnFailure
85
+ ? (attemptIndex) => Math.min(1000 * Math.pow(2, attemptIndex), 10000)
86
+ : undefined,
83
87
  });
84
88
  }
85
89
  /** Looks up the created subscription biId after success. */
@@ -1 +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 {\n CheckoutClient, CartStatusResult, BillingPlansResult, CourseDetail,\n} 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/** Checks whether the authenticated learner already has an active subscription. */\nexport function useCurrentUserSubscriberQuery(client: CheckoutClient | null, sessionReady: boolean) {\n return useQuery({\n queryKey: ['checkout', 'currentUserSubscriber'],\n enabled: !!client && sessionReady,\n queryFn: () => client!.isCurrentUserSubscriber(),\n staleTime: 5 * 60 * 1000,\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"]}
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 {\n CheckoutClient, CartStatusResult, BillingPlansResult, CourseDetail,\n} 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/** Checks whether the authenticated learner already has an active subscription. */\nexport function useCurrentUserSubscriberQuery(client: CheckoutClient | null, sessionReady: boolean) {\n return useQuery({\n queryKey: ['checkout', 'currentUserSubscriber'],\n enabled: !!client && sessionReady,\n queryFn: () => client!.isCurrentUserSubscriber(),\n staleTime: 5 * 60 * 1000,\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(\n client: CheckoutClient | null,\n cartBiId: string | null,\n retryOnFailure: boolean | number = false,\n) {\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 retry: retryOnFailure,\n retryDelay: retryOnFailure\n ? (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000)\n : undefined,\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edx/frontend-app-subscription-checkout",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
4
4
  "description": "Subscription Checkout Frontend application",
5
5
  "repository": {
6
6
  "type": "git",