@edx/frontend-app-alacarte-checkout 1.21.0 → 1.23.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 (45) hide show
  1. package/dist/components/Checkout/Checkout.js +6 -2
  2. package/dist/components/Checkout/Checkout.js.map +1 -1
  3. package/dist/components/PaymentForm/Messages.d.ts +10 -0
  4. package/dist/components/PaymentForm/Messages.js +10 -0
  5. package/dist/components/PaymentForm/Messages.js.map +1 -1
  6. package/dist/components/PaymentForm/PaymentForm.js +41 -13
  7. package/dist/components/PaymentForm/PaymentForm.js.map +1 -1
  8. package/dist/components/PaymentTimeoutAlert/Messages.d.ts +13 -0
  9. package/dist/components/PaymentTimeoutAlert/Messages.js +15 -0
  10. package/dist/components/PaymentTimeoutAlert/Messages.js.map +1 -0
  11. package/dist/components/PaymentTimeoutAlert/PaymentTimeoutAlert.d.ts +6 -0
  12. package/dist/components/PaymentTimeoutAlert/PaymentTimeoutAlert.js +15 -0
  13. package/dist/components/PaymentTimeoutAlert/PaymentTimeoutAlert.js.map +1 -0
  14. package/dist/constants.d.ts +1 -0
  15. package/dist/constants.js +1 -0
  16. package/dist/constants.js.map +1 -1
  17. package/dist/data/hooks/useAlacarteCheckout.d.ts +4 -0
  18. package/dist/data/hooks/useAlacarteCheckout.js +17 -5
  19. package/dist/data/hooks/useAlacarteCheckout.js.map +1 -1
  20. package/dist/data/hooks/useAlacarteQueries.d.ts +1 -1
  21. package/dist/data/hooks/useAlacarteQueries.js +9 -2
  22. package/dist/data/hooks/useAlacarteQueries.js.map +1 -1
  23. package/dist/data/hooks/useCheckoutQueries.js +11 -0
  24. package/dist/data/hooks/useCheckoutQueries.js.map +1 -1
  25. package/dist/styles/components/checkout.scss +3 -3
  26. package/dist/types/alacarte.js.map +1 -1
  27. package/dist/types.d.ts +2 -0
  28. package/dist/types.js.map +1 -1
  29. package/dist/utils/alacarteApi.d.ts +2 -2
  30. package/dist/utils/alacarteApi.js +8 -8
  31. package/dist/utils/alacarteApi.js.map +1 -1
  32. package/dist/utils/alacarteQueries.d.ts +5 -5
  33. package/dist/utils/alacarteQueries.js +5 -3
  34. package/dist/utils/alacarteQueries.js.map +1 -1
  35. package/dist/utils/billingAddress.d.ts +15 -1
  36. package/dist/utils/billingAddress.js +64 -3
  37. package/dist/utils/billingAddress.js.map +1 -1
  38. package/dist/utils/graphqlClient.js +5 -0
  39. package/dist/utils/graphqlClient.js.map +1 -1
  40. package/dist/utils/stripeCard.js +14 -2
  41. package/dist/utils/stripeCard.js.map +1 -1
  42. package/dist/utils/timeoutErrors.d.ts +13 -0
  43. package/dist/utils/timeoutErrors.js +19 -0
  44. package/dist/utils/timeoutErrors.js.map +1 -0
  45. package/package.json +1 -1
@@ -32,6 +32,7 @@ import PaymentForm from '../PaymentForm/PaymentForm';
32
32
  import CountryUnavailableModal from '../CountryUnavailableModal/CountryUnavailableModal';
33
33
  import AlacarteNotice from '../AlacarteNotice/AlacarteNotice';
34
34
  import AlacarteConfirmation from '../AlacarteConfirmation/AlacarteConfirmation';
35
+ import PaymentTimeoutAlert from '../PaymentTimeoutAlert/PaymentTimeoutAlert';
35
36
  import AlacarteDebugPanel from '../AlacarteDebugPanel/AlacarteDebugPanel'; // TEMPORARY — remove alongside AlacarteDebugPanel
36
37
  import { getTrialDateRange } from '../../utils';
37
38
  import { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';
@@ -203,9 +204,12 @@ const Checkout = (_a) => {
203
204
  return (_jsxs(_Fragment, { children: [alacarteDebug, _jsx(Row, { className: "checkout__container bg-light-200", children: _jsx(Col, { xs: 12, children: _jsx(Alert, { variant: "danger", icon: ErrorIcon, "data-testid": "alacarte-error-banner", children: alacarte.error || 'Something went wrong with checkout.' }) }) })] }));
204
205
  }
205
206
  const isAlreadyOwned = alacarte.isAlreadyOwned;
206
- return (_jsxs(_Fragment, { children: [alacarteDebug, _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, className: isAlreadyOwned ? 'checkout__owned-overlay' : '', 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 mb-4", children: "Checkout" }), isAlreadyOwned && (_jsxs(Alert, { variant: "danger", icon: ErrorIcon, className: "checkout__already-owned-alert mb-3", "data-testid": "already-owned-alert", children: [_jsx("p", { className: "mb-3", children: formatMessage(((_p = alacarte.selector) === null || _p === void 0 ? void 0 : _p.kind) === 'program'
207
+ const { paymentTimedOut } = alacarte;
208
+ // Grey out and block the form + summary; only the alert above stays usable.
209
+ const isLocked = isAlreadyOwned || paymentTimedOut;
210
+ return (_jsxs(_Fragment, { children: [alacarteDebug, _jsxs(Row, { className: "checkout__container bg-light-200", children: [_jsx(CountryUnavailableModal, { isOpen: isBillingCountryBlocked, homeUrl: homeUrl }), _jsxs(Col, { xs: 12, className: "d-lg-none", children: [_jsx("h1", { className: "font-weight-bold text-primary-900", children: "Checkout" }), paymentTimedOut && _jsx(PaymentTimeoutAlert, { className: "mb-3" })] }), _jsx(Col, { xs: 12, className: isLocked ? 'checkout__locked-overlay' : '', 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 mb-4", children: "Checkout" }), paymentTimedOut && (_jsx(PaymentTimeoutAlert, { className: "checkout__overlay-alert d-none d-lg-flex mb-3" })), isAlreadyOwned && (_jsxs(Alert, { variant: "danger", icon: ErrorIcon, className: "checkout__overlay-alert mb-3", "data-testid": "already-owned-alert", children: [_jsx("p", { className: "mb-3", children: formatMessage(((_p = alacarte.selector) === null || _p === void 0 ? void 0 : _p.kind) === 'program'
207
211
  ? messages.alreadyPaidProgram
208
- : messages.alreadyPaidCourse) }), _jsxs("div", { className: "d-flex align-items-center justify-content-end gap-3 flex-wrap", children: [orderHistoryUrl && (_jsx("a", { href: orderHistoryUrl, className: "text-gray-900 font-weight-bold", children: formatMessage(messages.viewOrderHistory) })), _jsx(Button, { variant: "brand", className: "rounded-pill", onClick: handleStartCourse, children: formatMessage(messages.goToCourse) })] })] })), c.error && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: c.clearError, children: c.error })), alacarte.placeOrderError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearPlaceOrderError, className: "mb-3", children: alacarte.placeOrderError })), ((_q = alacarte.paymentDecline) === null || _q === void 0 ? void 0 : _q.message) && !alacarte.placeOrderError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", "data-testid": "payment-decline-alert", children: getLearnerFacingStripeMessage({
212
+ : messages.alreadyPaidCourse) }), _jsxs("div", { className: "d-flex align-items-center justify-content-end gap-3 flex-wrap", children: [orderHistoryUrl && (_jsx("a", { href: orderHistoryUrl, className: "text-gray-900 font-weight-bold", children: formatMessage(messages.viewOrderHistory) })), _jsx(Button, { variant: "brand", className: "rounded-pill", onClick: handleStartCourse, children: formatMessage(messages.goToCourse) })] })] })), c.error && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: c.clearError, children: c.error })), alacarte.placeOrderError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearPlaceOrderError, className: "mb-3", children: alacarte.placeOrderError })), ((_q = alacarte.paymentDecline) === null || _q === void 0 ? void 0 : _q.message) && !alacarte.placeOrderError && !paymentTimedOut && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", "data-testid": "payment-decline-alert", children: getLearnerFacingStripeMessage({
209
213
  message: alacarte.paymentDecline.message,
210
214
  code: (_r = alacarte.paymentDecline.code) !== null && _r !== void 0 ? _r : undefined,
211
215
  }) })), alacarte.couponError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearCouponError, className: "mb-3", "data-testid": "coupon-error-alert", children: alacarte.couponError })), !alacarte.priceAccepted && isAlacarteReady && ((_s = alacarte.line) === null || _s === void 0 ? void 0 : _s.amountDue) && (_jsx(Alert, { variant: "info", className: "mb-3", "data-testid": "price-accept-notice", children: formatMessage(messages.priceChangedNotice, {
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../../../src/components/Checkout/Checkout.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useCallback, useEffect, useState } from 'react';\nimport { Alert, Button, Col, Row } from '@openedx/paragon';\nimport { CheckCircle, 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 { useAlacarteCheckout } from '../../data/hooks/useAlacarteCheckout';\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 AlacarteNotice from '../AlacarteNotice/AlacarteNotice';\nimport AlacarteConfirmation from '../AlacarteConfirmation/AlacarteConfirmation';\nimport AlacarteDebugPanel from '../AlacarteDebugPanel/AlacarteDebugPanel'; // TEMPORARY — remove alongside AlacarteDebugPanel\nimport { getTrialDateRange } from '@src/utils';\nimport { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';\nimport { appliedDiscountPercent } from '../../utils/discount';\nimport { confirmPaymentWithMethodId, getLearnerFacingStripeMessage } from '../../utils/stripeCard';\nimport { SuccessScreen, BlockedScreen, ProcessingScreen } from '../StatusScreens/StatusScreens';\nimport type { BillingCycle, CourseDetail } from '../../types';\nimport type { ProgramDetail } from '../../types/alacarte';\nimport messages from './Messages';\n\n// TEMPORARY — redirect-home-on-noActiveCheckout disabled per request; shows a\n// banner instead so the case is visible while the flow is being verified.\n// Flip back to true to restore the redirect.\nconst REDIRECT_ON_NO_ACTIVE_CHECKOUT = false;\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 /** Learner dashboard / order history URL for confirmation CTAs. */\n orderHistoryUrl?: string,\n};\n\nconst Checkout = ({\n homeUrl = '/',\n orderHistoryUrl,\n ...props\n}: CheckoutProps) => {\n const { formatMessage } = useIntl();\n const alacarte = useAlacarteCheckout({\n apiUrl: props.apiUrl,\n edxSessionUrl: props.edxSessionUrl,\n skipSubscriptionCourseRuns: props.skipSubscriptionCourseRuns,\n });\n const c = useCheckout(props);\n const [promoCodeValue, setPromoCodeValue] = useState('');\n const [dismissedCouponAlert, setDismissedCouponAlert] = useState<string | null>(null);\n const [showValidationBanner, setShowValidationBanner] = useState(false);\n // Last code we successfully priced — drives the \"Save {percent}% with code\n // {code}\" hint on the empty field while a coupon is not yet applied.\n const [advertisedOffer, setAdvertisedOffer] = useState<{ code: string, percent: number } | null>(null);\n const isAlacarteReady = (alacarte.phase === 'ready' || alacarte.phase === 'alreadyOwned') && !!alacarte.checkout;\n const appliedCouponCode = alacarte.checkout?.couponCode?.trim()\n ? alacarte.checkout.couponCode.trim()\n : null;\n const discountPercent = appliedDiscountPercent(alacarte.line);\n // Only treat the line discount as a removable coupon when the backend says\n // so (or a coupon code is present). Automatic offers stay on CartSummary\n // via discountName and must not drive PromoCode's applied/remove UI.\n const isCouponDiscount = !!alacarte.line?.discount\n && alacarte.line.discountSource !== 'automatic'\n && (alacarte.line.discountSource === 'coupon' || !!appliedCouponCode);\n const appliedDiscount = isCouponDiscount && discountPercent != null\n ? {\n percent: discountPercent,\n amount: alacarte.line!.discount!.amount,\n currency: alacarte.line!.discount!.currency,\n }\n : null;\n\n // Keep the coupon field in sync when a code is applied via URL or API.\n // Don't overwrite the field with empty when only an automatic offer applies.\n useEffect(() => {\n if (alacarte.checkout?.couponCode) {\n setPromoCodeValue(alacarte.checkout.couponCode);\n }\n }, [alacarte.checkout?.couponCode]);\n\n useEffect(() => {\n if (appliedCouponCode && isCouponDiscount && discountPercent != null) {\n setAdvertisedOffer({ code: appliedCouponCode, percent: discountPercent });\n }\n }, [appliedCouponCode, isCouponDiscount, discountPercent]);\n\n // No query params and no active cart — nothing to check out, send the\n // learner home rather than showing a placeholder.\n useEffect(() => {\n if (REDIRECT_ON_NO_ACTIVE_CHECKOUT && alacarte.phase === 'noActiveCheckout') {\n window.location.href = homeUrl;\n }\n }, [alacarte.phase, homeUrl]);\n\n // Express checkout (Apple Pay / Google Pay): runs the full place-order flow\n // using a wallet-provided PaymentMethod id instead of the mounted card element.\n const handleExpressPayment = useCallback(async (paymentMethodId: string, walletCountry?: string) => {\n if (!c.stripe) throw new Error('Stripe not loaded');\n const stripeInstance = c.stripe;\n const country = (c.billing.country || walletCountry || c.userCountry || '').trim().toUpperCase();\n if (!country) {\n throw new Error('Please select a country before using Apple Pay or Google Pay.');\n }\n\n await alacarte.placeOrderAsync({\n billing: {\n ...c.billing,\n country,\n },\n confirmCardPayment: async (clientSecret: string) => {\n await confirmPaymentWithMethodId({\n stripe: stripeInstance,\n clientSecret,\n paymentMethodId,\n });\n },\n });\n }, [alacarte, c.billing, c.userCountry, c.stripe]);\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 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 // Prefer the à la carte course's own detail (skills/badge/image, richer than\n // the subscription flow's ?course_run_key= lookup) when we selected a course.\n // When already-owned the line may be null, so fall back to the selector kind.\n const isCourseProduct = alacarte.line?.kind === 'course' || alacarte.selector?.kind === 'course';\n const isProgramProduct = alacarte.line?.kind === 'program' || alacarte.selector?.kind === 'program';\n\n const alacarteCourseDetail: CourseDetail | null\n = isCourseProduct && alacarte.productDetail && 'maId' in alacarte.productDetail\n ? alacarte.productDetail\n : null;\n const courseForSummary = alacarteCourseDetail ?? c.course;\n\n const alacarteProgramDetail: ProgramDetail | null\n = isProgramProduct && alacarte.productDetail && 'tCourses' in alacarte.productDetail\n ? alacarte.productDetail\n : null;\n\n const handleStartCourse = () => {\n const alacarteCourseUrl = alacarteCourseDetail?.tUrlCourse\n || (alacarte.productDetail && 'tUrlCourse' in alacarte.productDetail\n ? alacarte.productDetail.tUrlCourse\n : null);\n if (alacarteCourseUrl) {\n window.location.href = alacarteCourseUrl;\n } else if (c.course?.tUrlCourse) {\n window.location.href = c.course.tUrlCourse;\n } else {\n window.location.href = homeUrl || '/';\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 // TEMPORARY — flip to true to dump à la carte hook state while validating\n // against the real backend. Remove AlacarteDebugPanel once the flow is solid.\n const SHOW_ALACARTE_DEBUG = false;\n const alacarteDebug = SHOW_ALACARTE_DEBUG\n ? <AlacarteDebugPanel data={alacarte} />\n : null;\n\n // Confirmation: show once the order is ready (or failed to load). While\n // tPlacedOrder is still polling, keep the checkout form so Pay now can show\n // \"Processing...\" instead of a full-page loader.\n if (alacarte.placedOrder || alacarte.placedOrderError) {\n const confirmationTitle = alacarte.line?.kind === 'program'\n ? alacarte.line.programName\n : alacarte.line?.kind === 'course'\n ? alacarte.line.courseName\n : null;\n\n return (\n <>\n {alacarteDebug}\n <Row className=\"checkout__container alacarte-confirmation__container bg-light-200\">\n <Col xs={12}>\n <AlacarteConfirmation\n order={alacarte.placedOrder}\n awaiting={false}\n error={alacarte.placedOrderError}\n onContinue={handleStartCourse}\n productDetail={alacarte.productDetail}\n productTitle={confirmationTitle}\n ownedCourses={\n alacarte.line?.kind === 'program'\n ? (alacarte.line.ownedCourses ?? null)\n : null\n }\n orderHistoryUrl={orderHistoryUrl ?? null}\n placedAt={alacarte.placedOrderPlacedAt}\n />\n </Col>\n </Row>\n </>\n );\n }\n\n if (alacarte.phase === 'loading') {\n return (\n <>\n {alacarteDebug}\n <ProcessingScreen />\n </>\n );\n }\n if (alacarte.phase === 'noActiveCheckout' && REDIRECT_ON_NO_ACTIVE_CHECKOUT) {\n // Redirects home via the effect above — show a spinner rather than a\n // notice while that happens.\n return (\n <>\n {alacarteDebug}\n <ProcessingScreen />\n </>\n );\n }\n if (alacarte.phase === 'noActiveCheckout') {\n return (\n <>\n {alacarteDebug}\n <AlacarteNotice messageId={alacarte.noticeMessageId!} />\n </>\n );\n }\n // Product unavailable / not found / not purchasable — banner only, no checkout form.\n if (alacarte.phase === 'notPurchasable' || alacarte.phase === 'error') {\n return (\n <>\n {alacarteDebug}\n <Row className=\"checkout__container bg-light-200\">\n <Col xs={12}>\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n data-testid=\"alacarte-error-banner\"\n >\n {alacarte.error || 'Something went wrong with checkout.'}\n </Alert>\n </Col>\n </Row>\n </>\n );\n }\n\n const isAlreadyOwned = alacarte.isAlreadyOwned;\n\n return (\n <>\n {alacarteDebug}\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\n <Col xs={12} className={isAlreadyOwned ? 'checkout__owned-overlay' : ''}>\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 mb-4\">\n Checkout\n </h1>\n\n {isAlreadyOwned && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n className=\"checkout__already-owned-alert mb-3\"\n data-testid=\"already-owned-alert\"\n >\n <p className=\"mb-3\">\n {formatMessage(\n alacarte.selector?.kind === 'program'\n ? messages.alreadyPaidProgram\n : messages.alreadyPaidCourse,\n )}\n </p>\n <div className=\"d-flex align-items-center justify-content-end gap-3 flex-wrap\">\n {orderHistoryUrl && (\n <a href={orderHistoryUrl} className=\"text-gray-900 font-weight-bold\">\n {formatMessage(messages.viewOrderHistory)}\n </a>\n )}\n <Button variant=\"brand\" className=\"rounded-pill\" onClick={handleStartCourse}>\n {formatMessage(messages.goToCourse)}\n </Button>\n </div>\n </Alert>\n )}\n\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 {alacarte.placeOrderError && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={alacarte.clearPlaceOrderError}\n className=\"mb-3\"\n >\n {alacarte.placeOrderError}\n </Alert>\n )}\n\n {alacarte.paymentDecline?.message && !alacarte.placeOrderError && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n className=\"mb-3\"\n data-testid=\"payment-decline-alert\"\n >\n {getLearnerFacingStripeMessage({\n message: alacarte.paymentDecline.message,\n code: alacarte.paymentDecline.code ?? undefined,\n })}\n </Alert>\n )}\n\n {alacarte.couponError && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={alacarte.clearCouponError}\n className=\"mb-3\"\n data-testid=\"coupon-error-alert\"\n >\n {alacarte.couponError}\n </Alert>\n )}\n\n {!alacarte.priceAccepted && isAlacarteReady && alacarte.line?.amountDue && (\n <Alert variant=\"info\" className=\"mb-3\" data-testid=\"price-accept-notice\">\n {formatMessage(messages.priceChangedNotice, {\n amount: alacarte.line.amountDue.amount.toFixed(2),\n currency: alacarte.line.amountDue.currency,\n })}\n </Alert>\n )}\n\n {showForm && (\n <>\n {showValidationBanner && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {formatMessage(messages.validationBanner)}\n </Alert>\n )}\n {c.phase === 'failed' && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {failedMessage\n || formatMessage(messages.paymentProcessingDescription)}\n </Alert>\n )}\n {appliedCouponCode && appliedDiscount && dismissedCouponAlert !== appliedCouponCode && (\n <Alert\n variant=\"success\"\n icon={CheckCircle}\n dismissible\n closeLabel={formatMessage(messages.dismiss)}\n onClose={() => setDismissedCouponAlert(appliedCouponCode)}\n className=\"coupon-applied-alert\"\n data-testid=\"coupon-applied-alert\"\n >\n <span aria-hidden=\"true\">🎉 </span>\n {formatMessage(messages.couponAppliedAlert)}\n </Alert>\n )}\n {alacarte.removedCouponCode && (() => {\n const removedCode = alacarte.removedCouponCode;\n const removedText = formatMessage(\n messages.couponRemovedAlert,\n { code: removedCode },\n );\n // Bold the interpolated code without baking markup into the\n // translation string — find it in the formatted sentence.\n const codeIndex = removedText.indexOf(removedCode);\n return (\n <Alert\n variant=\"success\"\n icon={CheckCircle}\n dismissible\n closeLabel={formatMessage(messages.dismiss)}\n onClose={alacarte.clearRemovedCouponCode}\n className=\"coupon-removed-alert\"\n data-testid=\"coupon-removed-alert\"\n >\n {codeIndex === -1 ? removedText : (\n <>\n {removedText.slice(0, codeIndex)}\n <strong>{removedCode}</strong>\n {removedText.slice(codeIndex + removedCode.length)}\n </>\n )}\n </Alert>\n );\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 cardFieldStates={c.cardFieldStates}\n stripeReady={c.stripeReady}\n sessionReady={c.sessionReady}\n submitting={\n isAlacarteReady\n ? (alacarte.placingOrder || alacarte.awaitingPlacedOrder)\n : c.processingSubscription\n }\n onPlaceOrder={\n isAlacarteReady\n ? () => {\n alacarte.placeOrder({\n billing: {\n ...c.billing,\n // Country is required on tCheckoutPlaceOrder (two-letter ISO).\n // Prefer the form selection; fall back to gate geolocation.\n country: c.billing.country || c.userCountry || '',\n },\n confirmCardPayment: c.confirmCardPayment,\n });\n }\n : c.placeOrder\n }\n onValidationError={setShowValidationBanner}\n trialEnd={selectedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={null}\n cycleToShow={selectedCycle === 'monthly' ? 'monthly' : 'annual'}\n userCountry={c.userCountry}\n geolocationUrl={props.geolocationUrl}\n alacarteLine={alacarte.line}\n stripe={c.stripe}\n expressCountry={c.billing.country || c.userCountry || 'US'}\n onExpressPayment={isAlacarteReady ? handleExpressPayment : undefined}\n />\n </>\n )}\n\n {c.phase === 'success' && (\n <SuccessScreen\n subscriptionBiId={c.subscriptionDetails?.biId || ''}\n cardLast4={c.subscriptionDetails?.cardLast4 || ''}\n purchaseDate={displayStart}\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 course={c.course}\n onStartCourse={handleStartCourse}\n />\n ) : (\n <CartSummary\n defaultCycle={selectedCycle}\n onCycleChange={c.processingSubscription ? undefined : c.setCycle}\n course={courseForSummary}\n alacarteLine={alacarte.line}\n programDetail={alacarteProgramDetail}\n programName={alacarte.ownedProductName}\n promoCode={isAlacarteReady ? {\n value: promoCodeValue,\n onChange: (next) => {\n setPromoCodeValue(next);\n if (alacarte.couponError) alacarte.clearCouponError();\n },\n onApply: () => alacarte.applyCoupon(promoCodeValue),\n onRemove: () => {\n alacarte.removeCoupon();\n setPromoCodeValue('');\n setAdvertisedOffer(null);\n },\n appliedCode: appliedCouponCode,\n discount: appliedDiscount,\n offer: !appliedCouponCode ? advertisedOffer : null,\n error: alacarte.couponError,\n isApplying: alacarte.couponApplying,\n disabled: alacarte.placingOrder,\n } : null}\n />\n )}\n </Col>\n </Row>\n </Col>\n </Row>\n </>\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, { useCallback, useEffect, useState } from 'react';\nimport { Alert, Button, Col, Row } from '@openedx/paragon';\nimport { CheckCircle, 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 { useAlacarteCheckout } from '../../data/hooks/useAlacarteCheckout';\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 AlacarteNotice from '../AlacarteNotice/AlacarteNotice';\nimport AlacarteConfirmation from '../AlacarteConfirmation/AlacarteConfirmation';\nimport PaymentTimeoutAlert from '../PaymentTimeoutAlert/PaymentTimeoutAlert';\nimport AlacarteDebugPanel from '../AlacarteDebugPanel/AlacarteDebugPanel'; // TEMPORARY — remove alongside AlacarteDebugPanel\nimport { getTrialDateRange } from '@src/utils';\nimport { getLearnerFacingCheckoutMessage } from '../../utils/checkoutErrors';\nimport { appliedDiscountPercent } from '../../utils/discount';\nimport { confirmPaymentWithMethodId, getLearnerFacingStripeMessage } from '../../utils/stripeCard';\nimport { SuccessScreen, BlockedScreen, ProcessingScreen } from '../StatusScreens/StatusScreens';\nimport type { BillingCycle, CourseDetail } from '../../types';\nimport type { ProgramDetail } from '../../types/alacarte';\nimport messages from './Messages';\n\n// TEMPORARY — redirect-home-on-noActiveCheckout disabled per request; shows a\n// banner instead so the case is visible while the flow is being verified.\n// Flip back to true to restore the redirect.\nconst REDIRECT_ON_NO_ACTIVE_CHECKOUT = false;\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 /** Learner dashboard / order history URL for confirmation CTAs. */\n orderHistoryUrl?: string,\n};\n\nconst Checkout = ({\n homeUrl = '/',\n orderHistoryUrl,\n ...props\n}: CheckoutProps) => {\n const { formatMessage } = useIntl();\n const alacarte = useAlacarteCheckout({\n apiUrl: props.apiUrl,\n edxSessionUrl: props.edxSessionUrl,\n skipSubscriptionCourseRuns: props.skipSubscriptionCourseRuns,\n });\n const c = useCheckout(props);\n const [promoCodeValue, setPromoCodeValue] = useState('');\n const [dismissedCouponAlert, setDismissedCouponAlert] = useState<string | null>(null);\n const [showValidationBanner, setShowValidationBanner] = useState(false);\n // Last code we successfully priced — drives the \"Save {percent}% with code\n // {code}\" hint on the empty field while a coupon is not yet applied.\n const [advertisedOffer, setAdvertisedOffer] = useState<{ code: string, percent: number } | null>(null);\n const isAlacarteReady = (alacarte.phase === 'ready' || alacarte.phase === 'alreadyOwned') && !!alacarte.checkout;\n const appliedCouponCode = alacarte.checkout?.couponCode?.trim()\n ? alacarte.checkout.couponCode.trim()\n : null;\n const discountPercent = appliedDiscountPercent(alacarte.line);\n // Only treat the line discount as a removable coupon when the backend says\n // so (or a coupon code is present). Automatic offers stay on CartSummary\n // via discountName and must not drive PromoCode's applied/remove UI.\n const isCouponDiscount = !!alacarte.line?.discount\n && alacarte.line.discountSource !== 'automatic'\n && (alacarte.line.discountSource === 'coupon' || !!appliedCouponCode);\n const appliedDiscount = isCouponDiscount && discountPercent != null\n ? {\n percent: discountPercent,\n amount: alacarte.line!.discount!.amount,\n currency: alacarte.line!.discount!.currency,\n }\n : null;\n\n // Keep the coupon field in sync when a code is applied via URL or API.\n // Don't overwrite the field with empty when only an automatic offer applies.\n useEffect(() => {\n if (alacarte.checkout?.couponCode) {\n setPromoCodeValue(alacarte.checkout.couponCode);\n }\n }, [alacarte.checkout?.couponCode]);\n\n useEffect(() => {\n if (appliedCouponCode && isCouponDiscount && discountPercent != null) {\n setAdvertisedOffer({ code: appliedCouponCode, percent: discountPercent });\n }\n }, [appliedCouponCode, isCouponDiscount, discountPercent]);\n\n // No query params and no active cart — nothing to check out, send the\n // learner home rather than showing a placeholder.\n useEffect(() => {\n if (REDIRECT_ON_NO_ACTIVE_CHECKOUT && alacarte.phase === 'noActiveCheckout') {\n window.location.href = homeUrl;\n }\n }, [alacarte.phase, homeUrl]);\n\n // Express checkout (Apple Pay / Google Pay): runs the full place-order flow\n // using a wallet-provided PaymentMethod id instead of the mounted card element.\n const handleExpressPayment = useCallback(async (paymentMethodId: string, walletCountry?: string) => {\n if (!c.stripe) throw new Error('Stripe not loaded');\n const stripeInstance = c.stripe;\n const country = (c.billing.country || walletCountry || c.userCountry || '').trim().toUpperCase();\n if (!country) {\n throw new Error('Please select a country before using Apple Pay or Google Pay.');\n }\n\n await alacarte.placeOrderAsync({\n billing: {\n ...c.billing,\n country,\n },\n confirmCardPayment: async (clientSecret: string) => {\n await confirmPaymentWithMethodId({\n stripe: stripeInstance,\n clientSecret,\n paymentMethodId,\n });\n },\n });\n }, [alacarte, c.billing, c.userCountry, c.stripe]);\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 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 // Prefer the à la carte course's own detail (skills/badge/image, richer than\n // the subscription flow's ?course_run_key= lookup) when we selected a course.\n // When already-owned the line may be null, so fall back to the selector kind.\n const isCourseProduct = alacarte.line?.kind === 'course' || alacarte.selector?.kind === 'course';\n const isProgramProduct = alacarte.line?.kind === 'program' || alacarte.selector?.kind === 'program';\n\n const alacarteCourseDetail: CourseDetail | null\n = isCourseProduct && alacarte.productDetail && 'maId' in alacarte.productDetail\n ? alacarte.productDetail\n : null;\n const courseForSummary = alacarteCourseDetail ?? c.course;\n\n const alacarteProgramDetail: ProgramDetail | null\n = isProgramProduct && alacarte.productDetail && 'tCourses' in alacarte.productDetail\n ? alacarte.productDetail\n : null;\n\n const handleStartCourse = () => {\n const alacarteCourseUrl = alacarteCourseDetail?.tUrlCourse\n || (alacarte.productDetail && 'tUrlCourse' in alacarte.productDetail\n ? alacarte.productDetail.tUrlCourse\n : null);\n if (alacarteCourseUrl) {\n window.location.href = alacarteCourseUrl;\n } else if (c.course?.tUrlCourse) {\n window.location.href = c.course.tUrlCourse;\n } else {\n window.location.href = homeUrl || '/';\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 // TEMPORARY — flip to true to dump à la carte hook state while validating\n // against the real backend. Remove AlacarteDebugPanel once the flow is solid.\n const SHOW_ALACARTE_DEBUG = false;\n const alacarteDebug = SHOW_ALACARTE_DEBUG\n ? <AlacarteDebugPanel data={alacarte} />\n : null;\n\n // Confirmation: show once the order is ready (or failed to load). While\n // tPlacedOrder is still polling, keep the checkout form so Pay now can show\n // \"Processing...\" instead of a full-page loader.\n if (alacarte.placedOrder || alacarte.placedOrderError) {\n const confirmationTitle = alacarte.line?.kind === 'program'\n ? alacarte.line.programName\n : alacarte.line?.kind === 'course'\n ? alacarte.line.courseName\n : null;\n\n return (\n <>\n {alacarteDebug}\n <Row className=\"checkout__container alacarte-confirmation__container bg-light-200\">\n <Col xs={12}>\n <AlacarteConfirmation\n order={alacarte.placedOrder}\n awaiting={false}\n error={alacarte.placedOrderError}\n onContinue={handleStartCourse}\n productDetail={alacarte.productDetail}\n productTitle={confirmationTitle}\n ownedCourses={\n alacarte.line?.kind === 'program'\n ? (alacarte.line.ownedCourses ?? null)\n : null\n }\n orderHistoryUrl={orderHistoryUrl ?? null}\n placedAt={alacarte.placedOrderPlacedAt}\n />\n </Col>\n </Row>\n </>\n );\n }\n\n if (alacarte.phase === 'loading') {\n return (\n <>\n {alacarteDebug}\n <ProcessingScreen />\n </>\n );\n }\n if (alacarte.phase === 'noActiveCheckout' && REDIRECT_ON_NO_ACTIVE_CHECKOUT) {\n // Redirects home via the effect above — show a spinner rather than a\n // notice while that happens.\n return (\n <>\n {alacarteDebug}\n <ProcessingScreen />\n </>\n );\n }\n if (alacarte.phase === 'noActiveCheckout') {\n return (\n <>\n {alacarteDebug}\n <AlacarteNotice messageId={alacarte.noticeMessageId!} />\n </>\n );\n }\n // Product unavailable / not found / not purchasable — banner only, no checkout form.\n if (alacarte.phase === 'notPurchasable' || alacarte.phase === 'error') {\n return (\n <>\n {alacarteDebug}\n <Row className=\"checkout__container bg-light-200\">\n <Col xs={12}>\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n data-testid=\"alacarte-error-banner\"\n >\n {alacarte.error || 'Something went wrong with checkout.'}\n </Alert>\n </Col>\n </Row>\n </>\n );\n }\n\n const isAlreadyOwned = alacarte.isAlreadyOwned;\n const { paymentTimedOut } = alacarte;\n // Grey out and block the form + summary; only the alert above stays usable.\n const isLocked = isAlreadyOwned || paymentTimedOut;\n\n return (\n <>\n {alacarteDebug}\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 {/* Below lg the payment column renders under the summary\n (flex-column-reverse), so the warning goes up here instead. */}\n {paymentTimedOut && <PaymentTimeoutAlert className=\"mb-3\" />}\n </Col>\n\n <Col xs={12} className={isLocked ? 'checkout__locked-overlay' : ''}>\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 mb-4\">\n Checkout\n </h1>\n\n {paymentTimedOut && (\n <PaymentTimeoutAlert className=\"checkout__overlay-alert d-none d-lg-flex mb-3\" />\n )}\n\n {isAlreadyOwned && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n className=\"checkout__overlay-alert mb-3\"\n data-testid=\"already-owned-alert\"\n >\n <p className=\"mb-3\">\n {formatMessage(\n alacarte.selector?.kind === 'program'\n ? messages.alreadyPaidProgram\n : messages.alreadyPaidCourse,\n )}\n </p>\n <div className=\"d-flex align-items-center justify-content-end gap-3 flex-wrap\">\n {orderHistoryUrl && (\n <a href={orderHistoryUrl} className=\"text-gray-900 font-weight-bold\">\n {formatMessage(messages.viewOrderHistory)}\n </a>\n )}\n <Button variant=\"brand\" className=\"rounded-pill\" onClick={handleStartCourse}>\n {formatMessage(messages.goToCourse)}\n </Button>\n </div>\n </Alert>\n )}\n\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 {alacarte.placeOrderError && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={alacarte.clearPlaceOrderError}\n className=\"mb-3\"\n >\n {alacarte.placeOrderError}\n </Alert>\n )}\n\n {alacarte.paymentDecline?.message && !alacarte.placeOrderError && !paymentTimedOut && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n className=\"mb-3\"\n data-testid=\"payment-decline-alert\"\n >\n {getLearnerFacingStripeMessage({\n message: alacarte.paymentDecline.message,\n code: alacarte.paymentDecline.code ?? undefined,\n })}\n </Alert>\n )}\n\n {alacarte.couponError && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={alacarte.clearCouponError}\n className=\"mb-3\"\n data-testid=\"coupon-error-alert\"\n >\n {alacarte.couponError}\n </Alert>\n )}\n\n {!alacarte.priceAccepted && isAlacarteReady && alacarte.line?.amountDue && (\n <Alert variant=\"info\" className=\"mb-3\" data-testid=\"price-accept-notice\">\n {formatMessage(messages.priceChangedNotice, {\n amount: alacarte.line.amountDue.amount.toFixed(2),\n currency: alacarte.line.amountDue.currency,\n })}\n </Alert>\n )}\n\n {showForm && (\n <>\n {showValidationBanner && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {formatMessage(messages.validationBanner)}\n </Alert>\n )}\n {c.phase === 'failed' && (\n <Alert variant=\"danger\" icon={ErrorIcon} className=\"mb-3\">\n {failedMessage\n || formatMessage(messages.paymentProcessingDescription)}\n </Alert>\n )}\n {appliedCouponCode && appliedDiscount && dismissedCouponAlert !== appliedCouponCode && (\n <Alert\n variant=\"success\"\n icon={CheckCircle}\n dismissible\n closeLabel={formatMessage(messages.dismiss)}\n onClose={() => setDismissedCouponAlert(appliedCouponCode)}\n className=\"coupon-applied-alert\"\n data-testid=\"coupon-applied-alert\"\n >\n <span aria-hidden=\"true\">🎉 </span>\n {formatMessage(messages.couponAppliedAlert)}\n </Alert>\n )}\n {alacarte.removedCouponCode && (() => {\n const removedCode = alacarte.removedCouponCode;\n const removedText = formatMessage(\n messages.couponRemovedAlert,\n { code: removedCode },\n );\n // Bold the interpolated code without baking markup into the\n // translation string — find it in the formatted sentence.\n const codeIndex = removedText.indexOf(removedCode);\n return (\n <Alert\n variant=\"success\"\n icon={CheckCircle}\n dismissible\n closeLabel={formatMessage(messages.dismiss)}\n onClose={alacarte.clearRemovedCouponCode}\n className=\"coupon-removed-alert\"\n data-testid=\"coupon-removed-alert\"\n >\n {codeIndex === -1 ? removedText : (\n <>\n {removedText.slice(0, codeIndex)}\n <strong>{removedCode}</strong>\n {removedText.slice(codeIndex + removedCode.length)}\n </>\n )}\n </Alert>\n );\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 cardFieldStates={c.cardFieldStates}\n stripeReady={c.stripeReady}\n sessionReady={c.sessionReady}\n submitting={\n isAlacarteReady\n ? (alacarte.placingOrder || alacarte.awaitingPlacedOrder)\n : c.processingSubscription\n }\n onPlaceOrder={\n isAlacarteReady\n ? () => {\n alacarte.placeOrder({\n billing: {\n ...c.billing,\n // Country is required on tCheckoutPlaceOrder (two-letter ISO).\n // Prefer the form selection; fall back to gate geolocation.\n country: c.billing.country || c.userCountry || '',\n },\n confirmCardPayment: c.confirmCardPayment,\n });\n }\n : c.placeOrder\n }\n onValidationError={setShowValidationBanner}\n trialEnd={selectedCycle === 'monthly' ? displayEnd : undefined}\n priceToShow={null}\n cycleToShow={selectedCycle === 'monthly' ? 'monthly' : 'annual'}\n userCountry={c.userCountry}\n geolocationUrl={props.geolocationUrl}\n alacarteLine={alacarte.line}\n stripe={c.stripe}\n expressCountry={c.billing.country || c.userCountry || 'US'}\n onExpressPayment={isAlacarteReady ? handleExpressPayment : undefined}\n />\n </>\n )}\n\n {c.phase === 'success' && (\n <SuccessScreen\n subscriptionBiId={c.subscriptionDetails?.biId || ''}\n cardLast4={c.subscriptionDetails?.cardLast4 || ''}\n purchaseDate={displayStart}\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 course={c.course}\n onStartCourse={handleStartCourse}\n />\n ) : (\n <CartSummary\n defaultCycle={selectedCycle}\n onCycleChange={c.processingSubscription ? undefined : c.setCycle}\n course={courseForSummary}\n alacarteLine={alacarte.line}\n programDetail={alacarteProgramDetail}\n programName={alacarte.ownedProductName}\n promoCode={isAlacarteReady ? {\n value: promoCodeValue,\n onChange: (next) => {\n setPromoCodeValue(next);\n if (alacarte.couponError) alacarte.clearCouponError();\n },\n onApply: () => alacarte.applyCoupon(promoCodeValue),\n onRemove: () => {\n alacarte.removeCoupon();\n setPromoCodeValue('');\n setAdvertisedOffer(null);\n },\n appliedCode: appliedCouponCode,\n discount: appliedDiscount,\n offer: !appliedCouponCode ? advertisedOffer : null,\n error: alacarte.couponError,\n isApplying: alacarte.couponApplying,\n disabled: alacarte.placingOrder,\n } : null}\n />\n )}\n </Col>\n </Row>\n </Col>\n </Row>\n </>\n );\n};\n\nexport default Checkout;\n"]}
@@ -104,5 +104,15 @@ declare const messages: {
104
104
  defaultMessage: string;
105
105
  description: string;
106
106
  };
107
+ zipCodeInvalid: {
108
+ id: string;
109
+ defaultMessage: string;
110
+ description: string;
111
+ };
112
+ postalCodeInvalid: {
113
+ id: string;
114
+ defaultMessage: string;
115
+ description: string;
116
+ };
107
117
  };
108
118
  export default messages;
@@ -108,6 +108,16 @@ const messages = defineMessages({
108
108
  defaultMessage: 'This field is required',
109
109
  description: 'Error text shown below a required field that is empty',
110
110
  },
111
+ zipCodeInvalid: {
112
+ id: 'checkout.paymentForm.zipCodeInvalid',
113
+ defaultMessage: 'Enter a valid ZIP code',
114
+ description: 'Error text shown when a US ZIP code has an invalid format',
115
+ },
116
+ postalCodeInvalid: {
117
+ id: 'checkout.paymentForm.postalCodeInvalid',
118
+ defaultMessage: 'Enter a valid postal code',
119
+ description: 'Error text shown when a Canadian postal code has an invalid format',
120
+ },
111
121
  });
112
122
  export default messages;
113
123
  //# sourceMappingURL=Messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/PaymentForm/Messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n // Section headings\n selectPaymentMethod: {\n id: 'checkout.paymentForm.selectPaymentMethod',\n defaultMessage: 'Select Payment Method',\n description: 'Heading for the payment method selection section',\n },\n needAssistance: {\n id: 'checkout.paymentForm.needAssistance',\n defaultMessage: 'Need assistance?',\n description: 'Help text heading',\n },\n needAssistanceBody: {\n id: 'checkout.paymentForm.needAssistanceBody',\n defaultMessage: 'Visit the {link} to review purchase and refund policies.',\n description: 'Help text with learner help center link',\n },\n learnerHelpCenter: {\n id: 'checkout.paymentForm.learnerHelpCenter',\n defaultMessage: 'Learner Help Center',\n description: 'Learner help center link text',\n },\n\n payWithCard: {\n id: 'checkout.paymentForm.payWithCard',\n defaultMessage: 'Pay with card',\n description: 'Heading for the card payment fields',\n },\n\n // Order total\n orderDisclaimer: {\n id: 'checkout.paymentForm.orderDisclaimer',\n defaultMessage: 'After you complete your order you will be able to select course dates from your dashboard.',\n description: 'Disclaimer shown above the order total explaining taxes and enrollment',\n },\n total: {\n id: 'checkout.paymentForm.total',\n defaultMessage: 'Total:',\n description: 'Label for the order total amount',\n },\n totalAmount: {\n id: 'checkout.paymentForm.totalAmount',\n defaultMessage: '${amount} {currency}',\n description: 'Formatted order total with currency code e.g. $219.00 USD',\n },\n\n // Submit button\n payNow: {\n id: 'checkout.paymentForm.payNow',\n defaultMessage: 'Pay now',\n description: 'Submit button label',\n },\n processing: {\n id: 'checkout.paymentForm.processing',\n defaultMessage: 'Processing...',\n description: 'Submit button label while the order is being placed',\n },\n country: {\n id: 'checkout.paymentForm.country',\n defaultMessage: 'Country',\n description: 'Country selector label',\n },\n countryPlaceholder: {\n id: 'checkout.paymentForm.countryPlaceholder',\n defaultMessage: 'Select your country',\n description: 'Placeholder option shown before a country is selected',\n },\n state: {\n id: 'checkout.paymentForm.state',\n defaultMessage: 'State',\n description: 'State selector label (India)',\n },\n statePlaceholder: {\n id: 'checkout.paymentForm.statePlaceholder',\n defaultMessage: 'Select your state',\n description: 'Placeholder option shown before a state is selected',\n },\n province: {\n id: 'checkout.paymentForm.province',\n defaultMessage: 'Province',\n description: 'Province selector label (Canada)',\n },\n provincePlaceholder: {\n id: 'checkout.paymentForm.provincePlaceholder',\n defaultMessage: 'Select your province',\n description: 'Placeholder option shown before a province is selected',\n },\n zipCode: {\n id: 'checkout.paymentForm.zipCode',\n defaultMessage: 'ZIP Code',\n description: 'ZIP code label (United States)',\n },\n zipCodePlaceholder: {\n id: 'checkout.paymentForm.zipCodePlaceholder',\n defaultMessage: '12345',\n description: 'ZIP code input placeholder (United States)',\n },\n postalCode: {\n id: 'checkout.paymentForm.postalCode',\n defaultMessage: 'Postal code',\n description: 'Postal code label (Canada)',\n },\n postalCodePlaceholder: {\n id: 'checkout.paymentForm.postalCodePlaceholder',\n defaultMessage: 'A1A 1A1',\n description: 'Postal code input placeholder (Canada)',\n },\n fieldRequired: {\n id: 'checkout.paymentForm.fieldRequired',\n defaultMessage: 'This field is required',\n description: 'Error text shown below a required field that is empty',\n },\n});\n\nexport default messages;\n"]}
1
+ {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/PaymentForm/Messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n // Section headings\n selectPaymentMethod: {\n id: 'checkout.paymentForm.selectPaymentMethod',\n defaultMessage: 'Select Payment Method',\n description: 'Heading for the payment method selection section',\n },\n needAssistance: {\n id: 'checkout.paymentForm.needAssistance',\n defaultMessage: 'Need assistance?',\n description: 'Help text heading',\n },\n needAssistanceBody: {\n id: 'checkout.paymentForm.needAssistanceBody',\n defaultMessage: 'Visit the {link} to review purchase and refund policies.',\n description: 'Help text with learner help center link',\n },\n learnerHelpCenter: {\n id: 'checkout.paymentForm.learnerHelpCenter',\n defaultMessage: 'Learner Help Center',\n description: 'Learner help center link text',\n },\n\n payWithCard: {\n id: 'checkout.paymentForm.payWithCard',\n defaultMessage: 'Pay with card',\n description: 'Heading for the card payment fields',\n },\n\n // Order total\n orderDisclaimer: {\n id: 'checkout.paymentForm.orderDisclaimer',\n defaultMessage: 'After you complete your order you will be able to select course dates from your dashboard.',\n description: 'Disclaimer shown above the order total explaining taxes and enrollment',\n },\n total: {\n id: 'checkout.paymentForm.total',\n defaultMessage: 'Total:',\n description: 'Label for the order total amount',\n },\n totalAmount: {\n id: 'checkout.paymentForm.totalAmount',\n defaultMessage: '${amount} {currency}',\n description: 'Formatted order total with currency code e.g. $219.00 USD',\n },\n\n // Submit button\n payNow: {\n id: 'checkout.paymentForm.payNow',\n defaultMessage: 'Pay now',\n description: 'Submit button label',\n },\n processing: {\n id: 'checkout.paymentForm.processing',\n defaultMessage: 'Processing...',\n description: 'Submit button label while the order is being placed',\n },\n country: {\n id: 'checkout.paymentForm.country',\n defaultMessage: 'Country',\n description: 'Country selector label',\n },\n countryPlaceholder: {\n id: 'checkout.paymentForm.countryPlaceholder',\n defaultMessage: 'Select your country',\n description: 'Placeholder option shown before a country is selected',\n },\n state: {\n id: 'checkout.paymentForm.state',\n defaultMessage: 'State',\n description: 'State selector label (India)',\n },\n statePlaceholder: {\n id: 'checkout.paymentForm.statePlaceholder',\n defaultMessage: 'Select your state',\n description: 'Placeholder option shown before a state is selected',\n },\n province: {\n id: 'checkout.paymentForm.province',\n defaultMessage: 'Province',\n description: 'Province selector label (Canada)',\n },\n provincePlaceholder: {\n id: 'checkout.paymentForm.provincePlaceholder',\n defaultMessage: 'Select your province',\n description: 'Placeholder option shown before a province is selected',\n },\n zipCode: {\n id: 'checkout.paymentForm.zipCode',\n defaultMessage: 'ZIP Code',\n description: 'ZIP code label (United States)',\n },\n zipCodePlaceholder: {\n id: 'checkout.paymentForm.zipCodePlaceholder',\n defaultMessage: '12345',\n description: 'ZIP code input placeholder (United States)',\n },\n postalCode: {\n id: 'checkout.paymentForm.postalCode',\n defaultMessage: 'Postal code',\n description: 'Postal code label (Canada)',\n },\n postalCodePlaceholder: {\n id: 'checkout.paymentForm.postalCodePlaceholder',\n defaultMessage: 'A1A 1A1',\n description: 'Postal code input placeholder (Canada)',\n },\n fieldRequired: {\n id: 'checkout.paymentForm.fieldRequired',\n defaultMessage: 'This field is required',\n description: 'Error text shown below a required field that is empty',\n },\n zipCodeInvalid: {\n id: 'checkout.paymentForm.zipCodeInvalid',\n defaultMessage: 'Enter a valid ZIP code',\n description: 'Error text shown when a US ZIP code has an invalid format',\n },\n postalCodeInvalid: {\n id: 'checkout.paymentForm.postalCodeInvalid',\n defaultMessage: 'Enter a valid postal code',\n description: 'Error text shown when a Canadian postal code has an invalid format',\n },\n});\n\nexport default messages;\n"]}
@@ -13,13 +13,15 @@ import { Button, Form } from '@openedx/paragon';
13
13
  import { useIntl } from '@openedx/frontend-base';
14
14
  import PaymentFields from '../PaymentFields/PaymentFields';
15
15
  import ExpressCheckout from '../ExpressCheckout/ExpressCheckout';
16
- import { BILLING_COUNTRIES } from '../../constants';
17
- import { getBillingCountryFields, hasRequiredBillingFields } from '../../utils/billingAddress';
16
+ import { BILLING_COUNTRIES, LEARNER_HELP_CENTER_URL } from '../../constants';
17
+ import { getBillingCountryFields, getBillingPostalMaxLength, hasRequiredBillingFields, isValidBillingPostal, isValidBillingSubdivision, sanitizeBillingPostalInput, } from '../../utils/billingAddress';
18
18
  import messages from './Messages';
19
19
  const PaymentForm = ({ billing, setField, numberMountRef, expiryMountRef, cvcMountRef, stripeReady, sessionReady, submitting, onPlaceOrder, alacarteLine = null, stripe = null, expressCountry = 'US', onExpressPayment, cardFieldStates, onValidationError, }) => {
20
- var _a, _b;
20
+ var _a, _b, _c;
21
21
  const { formatMessage } = useIntl();
22
22
  const [showValidationErrors, setShowValidationErrors] = useState(false);
23
+ /** Postal format errors only after blur — cleared again while the user types. */
24
+ const [postalBlurred, setPostalBlurred] = useState(false);
23
25
  // No fallback amount — an unresolved à la carte line means we don't know
24
26
  // the price yet, so this is left blank rather than showing a made-up number.
25
27
  const totalText = (alacarteLine === null || alacarteLine === void 0 ? void 0 : alacarteLine.amountDue)
@@ -67,17 +69,39 @@ const PaymentForm = ({ billing, setField, numberMountRef, expiryMountRef, cvcMou
67
69
  }
68
70
  : undefined;
69
71
  const countryError = showValidationErrors && !billing.country ? requiredMsg : undefined;
70
- const stateError = showValidationErrors && countryFields.needsState && !billing.state.trim()
71
- ? requiredMsg
72
- : undefined;
73
- const postalError = showValidationErrors && countryFields.needsPostal && !billing.zip.trim()
74
- ? requiredMsg
75
- : undefined;
72
+ const stateError = (() => {
73
+ if (!countryFields.needsState)
74
+ return undefined;
75
+ if (!billing.state.trim()) {
76
+ return showValidationErrors ? requiredMsg : undefined;
77
+ }
78
+ // Subdivision is a select of known values — only surface if somehow invalid on submit.
79
+ if (showValidationErrors && !isValidBillingSubdivision(countryCode, billing.state)) {
80
+ return requiredMsg;
81
+ }
82
+ return undefined;
83
+ })();
84
+ const postalError = (() => {
85
+ if (!countryFields.needsPostal)
86
+ return undefined;
87
+ const zip = billing.zip.trim();
88
+ if (!zip) {
89
+ return showValidationErrors ? requiredMsg : undefined;
90
+ }
91
+ // Format check only after blur (or when Pay now forces validation).
92
+ if (!(postalBlurred || showValidationErrors))
93
+ return undefined;
94
+ if (!isValidBillingPostal(countryCode, zip)) {
95
+ return formatMessage(countryCode === 'US' ? messages.zipCodeInvalid : messages.postalCodeInvalid);
96
+ }
97
+ return undefined;
98
+ })();
76
99
  const handleCountryChange = useCallback((country) => {
77
100
  setField('country', country);
78
101
  // Subdivision / postal values are country-specific — clear them on change.
79
102
  setField('state', '');
80
103
  setField('zip', '');
104
+ setPostalBlurred(false);
81
105
  }, [setField]);
82
106
  // This design has no terms/consent checkboxes, so there's nothing for the
83
107
  // learner to opt into on screen — send a default consent record instead of
@@ -112,13 +136,17 @@ const PaymentForm = ({ billing, setField, numberMountRef, expiryMountRef, cvcMou
112
136
  setField('state', e.target.value);
113
137
  }, "aria-label": formatMessage(countryCode === 'CA' ? messages.province : messages.state), children: [_jsx("option", { value: "", disabled: true, hidden: true, children: formatMessage(countryCode === 'CA' ? messages.provincePlaceholder : messages.statePlaceholder) }), countryFields.subdivisions.map((subdivision) => (_jsx("option", { value: subdivision[0], children: subdivision[1] }, subdivision[0])))] }), stateError && (_jsxs("div", { className: "payment--field__error", role: "alert", children: [_jsx("span", { className: "payment--field__error-icon", "aria-hidden": "true" }), stateError] }))] })) : null;
114
138
  const postalControl = countryFields.needsPostal ? (_jsxs(Form.Group, { controlId: "postal", className: `mb-0 payment__field--postal${postalError ? ' payment__field--postal-error' : ''}`, children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode) }), _jsx(Form.Control, { value: billing.zip, onChange: (e) => {
115
- setField('zip', e.target.value);
116
- }, placeholder: formatMessage(countryCode === 'US' ? messages.zipCodePlaceholder : messages.postalCodePlaceholder), "aria-label": formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode), autoComplete: "postal-code" }), postalError && (_jsxs("div", { className: "payment--field__error", role: "alert", children: [_jsx("span", { className: "payment--field__error-icon", "aria-hidden": "true" }), postalError] }))] })) : null;
139
+ setField('zip', sanitizeBillingPostalInput(countryCode, e.target.value));
140
+ // Hide format errors while typing; re-validate on the next blur.
141
+ setPostalBlurred(false);
142
+ }, onBlur: () => {
143
+ setPostalBlurred(true);
144
+ }, maxLength: (_a = getBillingPostalMaxLength(countryCode)) !== null && _a !== void 0 ? _a : undefined, placeholder: formatMessage(countryCode === 'US' ? messages.zipCodePlaceholder : messages.postalCodePlaceholder), "aria-label": formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode), autoComplete: "postal-code" }), postalError && (_jsxs("div", { className: "payment--field__error", role: "alert", children: [_jsx("span", { className: "payment--field__error-icon", "aria-hidden": "true" }), postalError] }))] })) : null;
117
145
  return (_jsxs("div", { className: "payment-form bg-white", children: [_jsxs("div", { children: [_jsx("h2", { className: "payment-form__heading font-weight-bold mb-3 text-primary-500", children: formatMessage(messages.selectPaymentMethod) }), _jsxs("p", { className: "payment-form__help small mb-0", children: [_jsx("strong", { className: "d-block text-primary-500", children: formatMessage(messages.needAssistance) }), ' ', _jsx("span", { className: "text-gray-700 gap-y-2", children: formatMessage(messages.needAssistanceBody, {
118
- link: (_jsx("a", { href: "https://support.edx.org", target: "_blank", rel: "noreferrer", className: "text-gray-700", children: formatMessage(messages.learnerHelpCenter) })),
146
+ link: (_jsx("a", { href: LEARNER_HELP_CENTER_URL, target: "_blank", rel: "noreferrer", className: "text-gray-700", children: formatMessage(messages.learnerHelpCenter) })),
119
147
  }) })] })] }), _jsx(ExpressCheckout, { stripe: stripe, totalAmountCents: (alacarteLine === null || alacarteLine === void 0 ? void 0 : alacarteLine.amountDue)
120
148
  ? Math.round(alacarteLine.amountDue.amount * 100)
121
- : null, currency: (_b = (_a = alacarteLine === null || alacarteLine === void 0 ? void 0 : alacarteLine.amountDue) === null || _a === void 0 ? void 0 : _a.currency) !== null && _b !== void 0 ? _b : null, country: expressCountry, onPaymentAuthorized: onExpressPayment !== null && onExpressPayment !== void 0 ? onExpressPayment : (() => __awaiter(void 0, void 0, void 0, function* () { })),
149
+ : null, currency: (_c = (_b = alacarteLine === null || alacarteLine === void 0 ? void 0 : alacarteLine.amountDue) === null || _b === void 0 ? void 0 : _b.currency) !== null && _c !== void 0 ? _c : null, country: expressCountry, onPaymentAuthorized: onExpressPayment !== null && onExpressPayment !== void 0 ? onExpressPayment : (() => __awaiter(void 0, void 0, void 0, function* () { })),
122
150
  // Wallets need a real place-order handler (à la carte ready) — a missing
123
151
  // handler used to no-op after wallet auth and mark the sheet successful.
124
152
  disabled: isDisabled || !onExpressPayment }), _jsx("div", { className: "payment-form__methods", children: _jsx("div", { className: "payment-form__method payment-form__method--selected", children: _jsxs("div", { className: "payment-form__card-panel", children: [_jsx("h3", { className: "payment-form__card-heading font-weight-bold text-center text-primary-500 mb-3", children: formatMessage(messages.payWithCard) }), _jsx(PaymentFields, { numberMountRef: numberMountRef, expiryMountRef: expiryMountRef, cvcMountRef: cvcMountRef, fieldErrors: fieldErrors }), _jsx("div", { className: "payment-form__billing mt-3", children: countryFields.countryFullWidth ? (_jsxs(_Fragment, { children: [countryControl, (stateControl || postalControl) && (_jsxs("div", { className: "payment-form__billing-row", children: [stateControl, postalControl] }))] })) : (_jsxs("div", { className: `payment-form__billing-row${!stateControl && !postalControl ? ' payment-form__billing-row--single' : ''}`, children: [countryControl, stateControl, postalControl] })) })] }) }) }), _jsxs("div", { className: "payment-form__total", children: [_jsx("p", { className: "payment-form__total-disclaimer text-gray-700 mb-3", children: formatMessage(messages.orderDisclaimer) }), _jsxs("div", { className: "payment-form__total-row", children: [_jsxs("p", { className: "mb-0 text-gray-900", children: [_jsx("strong", { className: "payment-form__total-label", children: formatMessage(messages.total) }), ' ', _jsx("span", { className: "payment-form__total-value", children: totalText })] }), _jsx(Button, { variant: "brand", className: "payment-form__submit", onClick: handlePayNow, disabled: payNowDisabled, children: formatMessage(submitting ? messages.processing : messages.payNow) })] })] })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentForm.js","sourceRoot":"","sources":["../../../src/components/PaymentForm/PaymentForm.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useCallback } from 'react';\nimport type { Ref } from 'react';\nimport { Button, Form } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport PaymentFields from '../PaymentFields/PaymentFields';\nimport type { PaymentFieldErrors } from '../PaymentFields/PaymentFields';\nimport ExpressCheckout from '../ExpressCheckout/ExpressCheckout';\nimport type { BillingInfo, CardFieldStates, CheckoutConsent, StripeLike, SupportedPaymentMethod } from '../../types';\nimport type { AlacarteLine } from '../../types/alacarte';\nimport { BILLING_COUNTRIES } from '../../constants';\nimport { getBillingCountryFields, hasRequiredBillingFields } from '../../utils/billingAddress';\nimport messages from './Messages';\n\nexport interface PaymentFormProps {\n billing: BillingInfo,\n setField: (field: keyof BillingInfo, value: string) => void,\n numberMountRef: Ref<HTMLDivElement>,\n expiryMountRef: Ref<HTMLDivElement>,\n cvcMountRef: Ref<HTMLDivElement>,\n cardError: string,\n stripeReady: boolean,\n sessionReady: boolean,\n submitting: boolean,\n onPlaceOrder: (consent: CheckoutConsent, paymentMethod: SupportedPaymentMethod) => void,\n /** @deprecated Subscription plan price — unused for à la carte (see alacarteLine). */\n priceToShow?: { label?: string, amount?: string } | null,\n cycleToShow?: string,\n trialEnd?: string,\n userCountry?: string | null,\n /** Promotional monthly price e.g. \"39\" — monthly plans only. */\n promoAmount?: string,\n /** Length of the promotional period in months. */\n promoMonths?: number,\n /** Regular monthly price after the promo period e.g. \"59\". */\n monthlyRegularAmount?: string,\n geolocationUrl?: string,\n /** À la carte checkout line — when present, drives the order total shown. */\n alacarteLine?: AlacarteLine | null,\n /** Stripe.js instance for express checkout (Apple Pay / Google Pay). */\n stripe?: StripeLike | null,\n /** Two-letter country code for express checkout initialisation. */\n expressCountry?: string,\n /** Called when the user authorises a wallet payment. */\n onExpressPayment?: (paymentMethodId: string, walletCountry?: string) => Promise<void>,\n /** Tracks empty/complete state of each Stripe card element for validation. */\n cardFieldStates?: CardFieldStates,\n /** Called when Pay Now validation fails or succeeds — lets the parent show/hide a banner. */\n onValidationError?: (hasErrors: boolean) => void,\n}\n\nconst PaymentForm = ({\n billing,\n setField,\n numberMountRef,\n expiryMountRef,\n cvcMountRef,\n stripeReady,\n sessionReady,\n submitting,\n onPlaceOrder,\n alacarteLine = null,\n stripe = null,\n expressCountry = 'US',\n onExpressPayment,\n cardFieldStates,\n onValidationError,\n}: PaymentFormProps) => {\n const { formatMessage } = useIntl();\n const [showValidationErrors, setShowValidationErrors] = useState(false);\n\n // No fallback amount — an unresolved à la carte line means we don't know\n // the price yet, so this is left blank rather than showing a made-up number.\n const totalText = alacarteLine?.amountDue\n ? formatMessage(messages.totalAmount, {\n amount: alacarteLine.amountDue.amount.toFixed(2), currency: alacarteLine.amountDue.currency,\n })\n : '';\n\n const sessionBusy = submitting || !stripeReady || !sessionReady;\n const countryCode = billing.country.trim().toUpperCase();\n const countryFields = getBillingCountryFields(countryCode);\n\n const cardFieldsValid = !!cardFieldStates\n && cardFieldStates.number.complete\n && !cardFieldStates.number.empty\n && !cardFieldStates.number.error\n && cardFieldStates.expiry.complete\n && !cardFieldStates.expiry.empty\n && !cardFieldStates.expiry.error\n && cardFieldStates.cvc.complete\n && !cardFieldStates.cvc.empty\n && !cardFieldStates.cvc.error;\n const billingValid = hasRequiredBillingFields(billing);\n // Pay now stays disabled until Stripe Elements report complete, valid fields\n // and required billing fields are filled. Express checkout only needs session readiness.\n const isDisabled = sessionBusy;\n const payNowDisabled = sessionBusy || !cardFieldsValid || !billingValid;\n\n const requiredMsg = formatMessage(messages.fieldRequired);\n\n // Per-field error: show Stripe's inline error on blur, or \"required\" on submit.\n const fieldErrorFor = (field: 'number' | 'expiry' | 'cvc'): string | undefined => {\n const state = cardFieldStates?.[field];\n if (!state) return undefined;\n // Submit-time: empty fields show \"This field is required\"\n if (showValidationErrors && state.empty) return requiredMsg;\n // Blur-time: show Stripe's validation error once the user has left the field\n if (state.blurred && state.error) return state.error;\n return undefined;\n };\n\n const fieldErrors: PaymentFieldErrors | undefined = cardFieldStates\n ? {\n number: fieldErrorFor('number'),\n expiry: fieldErrorFor('expiry'),\n cvc: fieldErrorFor('cvc'),\n }\n : undefined;\n\n const countryError = showValidationErrors && !billing.country ? requiredMsg : undefined;\n const stateError = showValidationErrors && countryFields.needsState && !billing.state.trim()\n ? requiredMsg\n : undefined;\n const postalError = showValidationErrors && countryFields.needsPostal && !billing.zip.trim()\n ? requiredMsg\n : undefined;\n\n const handleCountryChange = useCallback((country: string) => {\n setField('country', country);\n // Subdivision / postal values are country-specific — clear them on change.\n setField('state', '');\n setField('zip', '');\n }, [setField]);\n\n // This design has no terms/consent checkboxes, so there's nothing for the\n // learner to opt into on screen — send a default consent record instead of\n // building it from UI state that doesn't exist here.\n const handlePayNow = useCallback(() => {\n // Check if any required field is empty.\n const numberEmpty = cardFieldStates?.number.empty ?? true;\n const expiryEmpty = cardFieldStates?.expiry.empty ?? true;\n const cvcEmpty = cardFieldStates?.cvc.empty ?? true;\n const billingMissing = !hasRequiredBillingFields(billing);\n\n if (numberEmpty || expiryEmpty || cvcEmpty || billingMissing) {\n setShowValidationErrors(true);\n onValidationError?.(true);\n return;\n }\n\n setShowValidationErrors(false);\n onValidationError?.(false);\n onPlaceOrder({\n tConsentRecurring: true,\n tConsentUkCa: null,\n tConsentAt: new Date().toISOString(),\n tConsentText: '',\n }, 'card');\n }, [cardFieldStates, billing, onPlaceOrder, onValidationError]);\n\n const countryControl = (\n <Form.Group\n controlId=\"country\"\n className={`mb-0 payment__field--country${countryError ? ' payment__field--country-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(messages.country)}\n </Form.Label>\n <Form.Control\n as=\"select\"\n value={billing.country}\n onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {\n handleCountryChange(e.target.value);\n }}\n aria-label={formatMessage(messages.country)}\n >\n <option value=\"\" disabled hidden>\n {formatMessage(messages.countryPlaceholder)}\n </option>\n {BILLING_COUNTRIES.map((country) => {\n return (\n <option key={country[0]} value={country[0]}>\n {country[1]}\n </option>\n );\n })}\n </Form.Control>\n {countryError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {countryError}\n </div>\n )}\n </Form.Group>\n );\n\n const stateControl = countryFields.needsState && countryFields.subdivisions ? (\n <Form.Group\n controlId=\"state\"\n className={`mb-0 payment__field--state${stateError ? ' payment__field--state-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(countryCode === 'CA' ? messages.province : messages.state)}\n </Form.Label>\n <Form.Control\n as=\"select\"\n value={billing.state}\n onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {\n setField('state', e.target.value);\n }}\n aria-label={formatMessage(countryCode === 'CA' ? messages.province : messages.state)}\n >\n <option value=\"\" disabled hidden>\n {formatMessage(\n countryCode === 'CA' ? messages.provincePlaceholder : messages.statePlaceholder,\n )}\n </option>\n {countryFields.subdivisions.map((subdivision) => (\n <option key={subdivision[0]} value={subdivision[0]}>\n {subdivision[1]}\n </option>\n ))}\n </Form.Control>\n {stateError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {stateError}\n </div>\n )}\n </Form.Group>\n ) : null;\n\n const postalControl = countryFields.needsPostal ? (\n <Form.Group\n controlId=\"postal\"\n className={`mb-0 payment__field--postal${postalError ? ' payment__field--postal-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode)}\n </Form.Label>\n <Form.Control\n value={billing.zip}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setField('zip', e.target.value);\n }}\n placeholder={formatMessage(\n countryCode === 'US' ? messages.zipCodePlaceholder : messages.postalCodePlaceholder,\n )}\n aria-label={formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode)}\n autoComplete=\"postal-code\"\n />\n {postalError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {postalError}\n </div>\n )}\n </Form.Group>\n ) : null;\n\n return (\n <div className=\"payment-form bg-white\">\n <div>\n <h2 className=\"payment-form__heading font-weight-bold mb-3 text-primary-500\">\n {formatMessage(messages.selectPaymentMethod)}\n </h2>\n\n <p className=\"payment-form__help small mb-0\">\n <strong className=\"d-block text-primary-500\">\n {formatMessage(messages.needAssistance)}\n </strong>{' '}\n <span className=\"text-gray-700 gap-y-2\">\n {formatMessage(messages.needAssistanceBody, {\n link: (\n <a\n href=\"https://support.edx.org\"\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-gray-700\"\n >\n {formatMessage(messages.learnerHelpCenter)}\n </a>\n ),\n })}\n </span>\n </p>\n </div>\n\n <ExpressCheckout\n stripe={stripe}\n totalAmountCents={\n alacarteLine?.amountDue\n ? Math.round(alacarteLine.amountDue.amount * 100)\n : null\n }\n currency={alacarteLine?.amountDue?.currency ?? null}\n country={expressCountry}\n onPaymentAuthorized={onExpressPayment ?? (async () => {})}\n // Wallets need a real place-order handler (à la carte ready) — a missing\n // handler used to no-op after wallet auth and mark the sheet successful.\n disabled={isDisabled || !onExpressPayment}\n />\n\n {/* ── Payment method ── */}\n <div className=\"payment-form__methods\">\n <div className=\"payment-form__method payment-form__method--selected\">\n <div className=\"payment-form__card-panel\">\n <h3 className=\"payment-form__card-heading font-weight-bold text-center text-primary-500 mb-3\">\n {formatMessage(messages.payWithCard)}\n </h3>\n <PaymentFields\n numberMountRef={numberMountRef}\n expiryMountRef={expiryMountRef}\n cvcMountRef={cvcMountRef}\n fieldErrors={fieldErrors}\n />\n <div className=\"payment-form__billing mt-3\">\n {countryFields.countryFullWidth ? (\n <>\n {countryControl}\n {(stateControl || postalControl) && (\n <div className=\"payment-form__billing-row\">\n {stateControl}\n {postalControl}\n </div>\n )}\n </>\n ) : (\n <div className={`payment-form__billing-row${\n !stateControl && !postalControl ? ' payment-form__billing-row--single' : ''\n }`}\n >\n {countryControl}\n {stateControl}\n {postalControl}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* ── Order total ── */}\n <div className=\"payment-form__total\">\n <p className=\"payment-form__total-disclaimer text-gray-700 mb-3\">\n {formatMessage(messages.orderDisclaimer)}\n </p>\n <div className=\"payment-form__total-row\">\n <p className=\"mb-0 text-gray-900\">\n <strong className=\"payment-form__total-label\">{formatMessage(messages.total)}</strong>{' '}\n <span className=\"payment-form__total-value\">\n {totalText}\n </span>\n </p>\n <Button\n variant=\"brand\"\n className=\"payment-form__submit\"\n onClick={handlePayNow}\n disabled={payNowDisabled}\n >\n {formatMessage(submitting ? messages.processing : messages.payNow)}\n </Button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PaymentForm;\n"]}
1
+ {"version":3,"file":"PaymentForm.js","sourceRoot":"","sources":["../../../src/components/PaymentForm/PaymentForm.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useCallback } from 'react';\nimport type { Ref } from 'react';\nimport { Button, Form } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport PaymentFields from '../PaymentFields/PaymentFields';\nimport type { PaymentFieldErrors } from '../PaymentFields/PaymentFields';\nimport ExpressCheckout from '../ExpressCheckout/ExpressCheckout';\nimport type { BillingInfo, CardFieldStates, CheckoutConsent, StripeLike, SupportedPaymentMethod } from '../../types';\nimport type { AlacarteLine } from '../../types/alacarte';\nimport { BILLING_COUNTRIES, LEARNER_HELP_CENTER_URL } from '../../constants';\nimport {\n getBillingCountryFields,\n getBillingPostalMaxLength,\n hasRequiredBillingFields,\n isValidBillingPostal,\n isValidBillingSubdivision,\n sanitizeBillingPostalInput,\n} from '../../utils/billingAddress';\nimport messages from './Messages';\n\nexport interface PaymentFormProps {\n billing: BillingInfo,\n setField: (field: keyof BillingInfo, value: string) => void,\n numberMountRef: Ref<HTMLDivElement>,\n expiryMountRef: Ref<HTMLDivElement>,\n cvcMountRef: Ref<HTMLDivElement>,\n cardError: string,\n stripeReady: boolean,\n sessionReady: boolean,\n submitting: boolean,\n onPlaceOrder: (consent: CheckoutConsent, paymentMethod: SupportedPaymentMethod) => void,\n /** @deprecated Subscription plan price — unused for à la carte (see alacarteLine). */\n priceToShow?: { label?: string, amount?: string } | null,\n cycleToShow?: string,\n trialEnd?: string,\n userCountry?: string | null,\n /** Promotional monthly price e.g. \"39\" — monthly plans only. */\n promoAmount?: string,\n /** Length of the promotional period in months. */\n promoMonths?: number,\n /** Regular monthly price after the promo period e.g. \"59\". */\n monthlyRegularAmount?: string,\n geolocationUrl?: string,\n /** À la carte checkout line — when present, drives the order total shown. */\n alacarteLine?: AlacarteLine | null,\n /** Stripe.js instance for express checkout (Apple Pay / Google Pay). */\n stripe?: StripeLike | null,\n /** Two-letter country code for express checkout initialisation. */\n expressCountry?: string,\n /** Called when the user authorises a wallet payment. */\n onExpressPayment?: (paymentMethodId: string, walletCountry?: string) => Promise<void>,\n /** Tracks empty/complete state of each Stripe card element for validation. */\n cardFieldStates?: CardFieldStates,\n /** Called when Pay Now validation fails or succeeds — lets the parent show/hide a banner. */\n onValidationError?: (hasErrors: boolean) => void,\n}\n\nconst PaymentForm = ({\n billing,\n setField,\n numberMountRef,\n expiryMountRef,\n cvcMountRef,\n stripeReady,\n sessionReady,\n submitting,\n onPlaceOrder,\n alacarteLine = null,\n stripe = null,\n expressCountry = 'US',\n onExpressPayment,\n cardFieldStates,\n onValidationError,\n}: PaymentFormProps) => {\n const { formatMessage } = useIntl();\n const [showValidationErrors, setShowValidationErrors] = useState(false);\n /** Postal format errors only after blur — cleared again while the user types. */\n const [postalBlurred, setPostalBlurred] = useState(false);\n\n // No fallback amount — an unresolved à la carte line means we don't know\n // the price yet, so this is left blank rather than showing a made-up number.\n const totalText = alacarteLine?.amountDue\n ? formatMessage(messages.totalAmount, {\n amount: alacarteLine.amountDue.amount.toFixed(2), currency: alacarteLine.amountDue.currency,\n })\n : '';\n\n const sessionBusy = submitting || !stripeReady || !sessionReady;\n const countryCode = billing.country.trim().toUpperCase();\n const countryFields = getBillingCountryFields(countryCode);\n\n const cardFieldsValid = !!cardFieldStates\n && cardFieldStates.number.complete\n && !cardFieldStates.number.empty\n && !cardFieldStates.number.error\n && cardFieldStates.expiry.complete\n && !cardFieldStates.expiry.empty\n && !cardFieldStates.expiry.error\n && cardFieldStates.cvc.complete\n && !cardFieldStates.cvc.empty\n && !cardFieldStates.cvc.error;\n const billingValid = hasRequiredBillingFields(billing);\n // Pay now stays disabled until Stripe Elements report complete, valid fields\n // and required billing fields are filled. Express checkout only needs session readiness.\n const isDisabled = sessionBusy;\n const payNowDisabled = sessionBusy || !cardFieldsValid || !billingValid;\n\n const requiredMsg = formatMessage(messages.fieldRequired);\n\n // Per-field error: show Stripe's inline error on blur, or \"required\" on submit.\n const fieldErrorFor = (field: 'number' | 'expiry' | 'cvc'): string | undefined => {\n const state = cardFieldStates?.[field];\n if (!state) return undefined;\n // Submit-time: empty fields show \"This field is required\"\n if (showValidationErrors && state.empty) return requiredMsg;\n // Blur-time: show Stripe's validation error once the user has left the field\n if (state.blurred && state.error) return state.error;\n return undefined;\n };\n\n const fieldErrors: PaymentFieldErrors | undefined = cardFieldStates\n ? {\n number: fieldErrorFor('number'),\n expiry: fieldErrorFor('expiry'),\n cvc: fieldErrorFor('cvc'),\n }\n : undefined;\n\n const countryError = showValidationErrors && !billing.country ? requiredMsg : undefined;\n\n const stateError = (() => {\n if (!countryFields.needsState) return undefined;\n if (!billing.state.trim()) {\n return showValidationErrors ? requiredMsg : undefined;\n }\n // Subdivision is a select of known values — only surface if somehow invalid on submit.\n if (showValidationErrors && !isValidBillingSubdivision(countryCode, billing.state)) {\n return requiredMsg;\n }\n return undefined;\n })();\n\n const postalError = (() => {\n if (!countryFields.needsPostal) return undefined;\n const zip = billing.zip.trim();\n if (!zip) {\n return showValidationErrors ? requiredMsg : undefined;\n }\n // Format check only after blur (or when Pay now forces validation).\n if (!(postalBlurred || showValidationErrors)) return undefined;\n if (!isValidBillingPostal(countryCode, zip)) {\n return formatMessage(\n countryCode === 'US' ? messages.zipCodeInvalid : messages.postalCodeInvalid,\n );\n }\n return undefined;\n })();\n\n const handleCountryChange = useCallback((country: string) => {\n setField('country', country);\n // Subdivision / postal values are country-specific — clear them on change.\n setField('state', '');\n setField('zip', '');\n setPostalBlurred(false);\n }, [setField]);\n\n // This design has no terms/consent checkboxes, so there's nothing for the\n // learner to opt into on screen — send a default consent record instead of\n // building it from UI state that doesn't exist here.\n const handlePayNow = useCallback(() => {\n // Check if any required field is empty.\n const numberEmpty = cardFieldStates?.number.empty ?? true;\n const expiryEmpty = cardFieldStates?.expiry.empty ?? true;\n const cvcEmpty = cardFieldStates?.cvc.empty ?? true;\n const billingMissing = !hasRequiredBillingFields(billing);\n\n if (numberEmpty || expiryEmpty || cvcEmpty || billingMissing) {\n setShowValidationErrors(true);\n onValidationError?.(true);\n return;\n }\n\n setShowValidationErrors(false);\n onValidationError?.(false);\n onPlaceOrder({\n tConsentRecurring: true,\n tConsentUkCa: null,\n tConsentAt: new Date().toISOString(),\n tConsentText: '',\n }, 'card');\n }, [cardFieldStates, billing, onPlaceOrder, onValidationError]);\n\n const countryControl = (\n <Form.Group\n controlId=\"country\"\n className={`mb-0 payment__field--country${countryError ? ' payment__field--country-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(messages.country)}\n </Form.Label>\n <Form.Control\n as=\"select\"\n value={billing.country}\n onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {\n handleCountryChange(e.target.value);\n }}\n aria-label={formatMessage(messages.country)}\n >\n <option value=\"\" disabled hidden>\n {formatMessage(messages.countryPlaceholder)}\n </option>\n {BILLING_COUNTRIES.map((country) => {\n return (\n <option key={country[0]} value={country[0]}>\n {country[1]}\n </option>\n );\n })}\n </Form.Control>\n {countryError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {countryError}\n </div>\n )}\n </Form.Group>\n );\n\n const stateControl = countryFields.needsState && countryFields.subdivisions ? (\n <Form.Group\n controlId=\"state\"\n className={`mb-0 payment__field--state${stateError ? ' payment__field--state-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(countryCode === 'CA' ? messages.province : messages.state)}\n </Form.Label>\n <Form.Control\n as=\"select\"\n value={billing.state}\n onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {\n setField('state', e.target.value);\n }}\n aria-label={formatMessage(countryCode === 'CA' ? messages.province : messages.state)}\n >\n <option value=\"\" disabled hidden>\n {formatMessage(\n countryCode === 'CA' ? messages.provincePlaceholder : messages.statePlaceholder,\n )}\n </option>\n {countryFields.subdivisions.map((subdivision) => (\n <option key={subdivision[0]} value={subdivision[0]}>\n {subdivision[1]}\n </option>\n ))}\n </Form.Control>\n {stateError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {stateError}\n </div>\n )}\n </Form.Group>\n ) : null;\n\n const postalControl = countryFields.needsPostal ? (\n <Form.Group\n controlId=\"postal\"\n className={`mb-0 payment__field--postal${postalError ? ' payment__field--postal-error' : ''}`}\n >\n <Form.Label className=\"payment--field__label text-gray-900\">\n {formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode)}\n </Form.Label>\n <Form.Control\n value={billing.zip}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setField('zip', sanitizeBillingPostalInput(countryCode, e.target.value));\n // Hide format errors while typing; re-validate on the next blur.\n setPostalBlurred(false);\n }}\n onBlur={() => {\n setPostalBlurred(true);\n }}\n maxLength={getBillingPostalMaxLength(countryCode) ?? undefined}\n placeholder={formatMessage(\n countryCode === 'US' ? messages.zipCodePlaceholder : messages.postalCodePlaceholder,\n )}\n aria-label={formatMessage(countryCode === 'US' ? messages.zipCode : messages.postalCode)}\n autoComplete=\"postal-code\"\n />\n {postalError && (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {postalError}\n </div>\n )}\n </Form.Group>\n ) : null;\n\n return (\n <div className=\"payment-form bg-white\">\n <div>\n <h2 className=\"payment-form__heading font-weight-bold mb-3 text-primary-500\">\n {formatMessage(messages.selectPaymentMethod)}\n </h2>\n\n <p className=\"payment-form__help small mb-0\">\n <strong className=\"d-block text-primary-500\">\n {formatMessage(messages.needAssistance)}\n </strong>{' '}\n <span className=\"text-gray-700 gap-y-2\">\n {formatMessage(messages.needAssistanceBody, {\n link: (\n <a\n href={LEARNER_HELP_CENTER_URL}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-gray-700\"\n >\n {formatMessage(messages.learnerHelpCenter)}\n </a>\n ),\n })}\n </span>\n </p>\n </div>\n\n <ExpressCheckout\n stripe={stripe}\n totalAmountCents={\n alacarteLine?.amountDue\n ? Math.round(alacarteLine.amountDue.amount * 100)\n : null\n }\n currency={alacarteLine?.amountDue?.currency ?? null}\n country={expressCountry}\n onPaymentAuthorized={onExpressPayment ?? (async () => {})}\n // Wallets need a real place-order handler (à la carte ready) — a missing\n // handler used to no-op after wallet auth and mark the sheet successful.\n disabled={isDisabled || !onExpressPayment}\n />\n\n {/* ── Payment method ── */}\n <div className=\"payment-form__methods\">\n <div className=\"payment-form__method payment-form__method--selected\">\n <div className=\"payment-form__card-panel\">\n <h3 className=\"payment-form__card-heading font-weight-bold text-center text-primary-500 mb-3\">\n {formatMessage(messages.payWithCard)}\n </h3>\n <PaymentFields\n numberMountRef={numberMountRef}\n expiryMountRef={expiryMountRef}\n cvcMountRef={cvcMountRef}\n fieldErrors={fieldErrors}\n />\n <div className=\"payment-form__billing mt-3\">\n {countryFields.countryFullWidth ? (\n <>\n {countryControl}\n {(stateControl || postalControl) && (\n <div className=\"payment-form__billing-row\">\n {stateControl}\n {postalControl}\n </div>\n )}\n </>\n ) : (\n <div className={`payment-form__billing-row${\n !stateControl && !postalControl ? ' payment-form__billing-row--single' : ''\n }`}\n >\n {countryControl}\n {stateControl}\n {postalControl}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* ── Order total ── */}\n <div className=\"payment-form__total\">\n <p className=\"payment-form__total-disclaimer text-gray-700 mb-3\">\n {formatMessage(messages.orderDisclaimer)}\n </p>\n <div className=\"payment-form__total-row\">\n <p className=\"mb-0 text-gray-900\">\n <strong className=\"payment-form__total-label\">{formatMessage(messages.total)}</strong>{' '}\n <span className=\"payment-form__total-value\">\n {totalText}\n </span>\n </p>\n <Button\n variant=\"brand\"\n className=\"payment-form__submit\"\n onClick={handlePayNow}\n disabled={payNowDisabled}\n >\n {formatMessage(submitting ? messages.processing : messages.payNow)}\n </Button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PaymentForm;\n"]}
@@ -0,0 +1,13 @@
1
+ declare const messages: {
2
+ paymentTimeoutWarning: {
3
+ id: string;
4
+ defaultMessage: string;
5
+ description: string;
6
+ };
7
+ learnerHelpCenter: {
8
+ id: string;
9
+ defaultMessage: string;
10
+ description: string;
11
+ };
12
+ };
13
+ export default messages;
@@ -0,0 +1,15 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+ const messages = defineMessages({
3
+ paymentTimeoutWarning: {
4
+ id: 'checkout.paymentTimeoutAlert.warning',
5
+ defaultMessage: "We haven't heard back from the payment provider. Don't try again yet. Check your email in a few minutes to see if your order went through, and contact the {link} if you don't hear from us.",
6
+ description: 'Warning shown when the payment provider times out while placing an order',
7
+ },
8
+ learnerHelpCenter: {
9
+ id: 'checkout.paymentTimeoutAlert.learnerHelpCenter',
10
+ defaultMessage: 'Learner Help Center',
11
+ description: 'Learner help center link text in the payment timeout warning',
12
+ },
13
+ });
14
+ export default messages;
15
+ //# sourceMappingURL=Messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/PaymentTimeoutAlert/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,qBAAqB,EAAE;QACrB,EAAE,EAAE,sCAAsC;QAC1C,cAAc,EAAE,8LAA8L;QAC9M,WAAW,EAAE,0EAA0E;KACxF;IACD,iBAAiB,EAAE;QACjB,EAAE,EAAE,gDAAgD;QACpD,cAAc,EAAE,qBAAqB;QACrC,WAAW,EAAE,8DAA8D;KAC5E;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n paymentTimeoutWarning: {\n id: 'checkout.paymentTimeoutAlert.warning',\n defaultMessage: \"We haven't heard back from the payment provider. Don't try again yet. Check your email in a few minutes to see if your order went through, and contact the {link} if you don't hear from us.\",\n description: 'Warning shown when the payment provider times out while placing an order',\n },\n learnerHelpCenter: {\n id: 'checkout.paymentTimeoutAlert.learnerHelpCenter',\n defaultMessage: 'Learner Help Center',\n description: 'Learner help center link text in the payment timeout warning',\n },\n});\n\nexport default messages;\n"]}
@@ -0,0 +1,6 @@
1
+ export interface PaymentTimeoutAlertProps {
2
+ className?: string;
3
+ }
4
+ /** Shown when the payment provider times out — the order may still go through. */
5
+ declare const PaymentTimeoutAlert: ({ className }: PaymentTimeoutAlertProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default PaymentTimeoutAlert;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Alert } from '@openedx/paragon';
3
+ import { WarningFilled } from '@openedx/paragon/icons';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import { LEARNER_HELP_CENTER_URL } from '../../constants';
6
+ import messages from './Messages';
7
+ /** Shown when the payment provider times out — the order may still go through. */
8
+ const PaymentTimeoutAlert = ({ className }) => {
9
+ const { formatMessage } = useIntl();
10
+ return (_jsx(Alert, { variant: "warning", icon: WarningFilled, className: className, "data-testid": "payment-timeout-alert", children: formatMessage(messages.paymentTimeoutWarning, {
11
+ link: (_jsx("a", { href: LEARNER_HELP_CENTER_URL, target: "_blank", rel: "noreferrer", className: "text-gray-900", children: formatMessage(messages.learnerHelpCenter) })),
12
+ }) }));
13
+ };
14
+ export default PaymentTimeoutAlert;
15
+ //# sourceMappingURL=PaymentTimeoutAlert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentTimeoutAlert.js","sourceRoot":"","sources":["../../../src/components/PaymentTimeoutAlert/PaymentTimeoutAlert.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAMlC,kFAAkF;AAClF,MAAM,mBAAmB,GAAG,CAAC,EAAE,SAAS,EAA4B,EAAE,EAAE;IACtE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,OAAO,CACL,KAAC,KAAK,IACJ,OAAO,EAAC,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,SAAS,iBACR,uBAAuB,YAElC,aAAa,CAAC,QAAQ,CAAC,qBAAqB,EAAE;YAC7C,IAAI,EAAE,CACJ,YACE,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,eAAe,YAExB,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GACxC,CACL;SACF,CAAC,GACI,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import React from 'react';\nimport { Alert } from '@openedx/paragon';\nimport { WarningFilled } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport { LEARNER_HELP_CENTER_URL } from '../../constants';\nimport messages from './Messages';\n\nexport interface PaymentTimeoutAlertProps {\n className?: string,\n}\n\n/** Shown when the payment provider times out — the order may still go through. */\nconst PaymentTimeoutAlert = ({ className }: PaymentTimeoutAlertProps) => {\n const { formatMessage } = useIntl();\n return (\n <Alert\n variant=\"warning\"\n icon={WarningFilled}\n className={className}\n data-testid=\"payment-timeout-alert\"\n >\n {formatMessage(messages.paymentTimeoutWarning, {\n link: (\n <a\n href={LEARNER_HELP_CENTER_URL}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-gray-900\"\n >\n {formatMessage(messages.learnerHelpCenter)}\n </a>\n ),\n })}\n </Alert>\n );\n};\n\nexport default PaymentTimeoutAlert;\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { CSSProperties } from 'react';
2
2
  export declare const appId = "org.openedx.frontend.app.aca.checkout";
3
3
  export declare const acaCheckoutRole = "org.openedx.frontend.role.aca.checkout";
4
+ export declare const LEARNER_HELP_CENTER_URL = "https://support.edx.org";
4
5
  export declare const STATUS: {
5
6
  readonly IN_CART: "IN_CART";
6
7
  readonly CONFIRM: "CONFIRM";