@edx/frontend-app-alacarte-checkout 1.16.0 → 1.17.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.
- package/dist/components/Checkout/Checkout.js +8 -1
- package/dist/components/Checkout/Checkout.js.map +1 -1
- package/dist/components/Checkout/Messages.d.ts +5 -0
- package/dist/components/Checkout/Messages.js +5 -0
- package/dist/components/Checkout/Messages.js.map +1 -1
- package/dist/data/hooks/useAlacarteCheckout.d.ts +4 -0
- package/dist/data/hooks/useAlacarteCheckout.js +10 -3
- package/dist/data/hooks/useAlacarteCheckout.js.map +1 -1
- package/dist/utils/couponErrors.d.ts +2 -2
- package/dist/utils/couponErrors.js +11 -3
- package/dist/utils/couponErrors.js.map +1 -1
- package/dist/utils/provision.js +2 -2
- package/dist/utils/provision.js.map +1 -1
- package/package.json +1 -1
|
@@ -211,7 +211,14 @@ const Checkout = (_a) => {
|
|
|
211
211
|
|| formatMessage(messages.paymentProcessingDescription) })), appliedCouponCode && appliedDiscount && dismissedCouponAlert !== appliedCouponCode && (_jsxs(Alert, { variant: "success", icon: CheckCircle, dismissible: true, closeLabel: formatMessage(messages.dismiss), onClose: () => setDismissedCouponAlert(appliedCouponCode), className: "coupon-applied-alert", "data-testid": "coupon-applied-alert", children: [_jsx("span", { "aria-hidden": "true", children: "\uD83C\uDF89 " }), formatMessage(messages.couponAppliedAlert, {
|
|
212
212
|
code: appliedCouponCode,
|
|
213
213
|
percent: appliedDiscount.percent,
|
|
214
|
-
})] })),
|
|
214
|
+
})] })), alacarte.removedCouponCode && (() => {
|
|
215
|
+
const removedCode = alacarte.removedCouponCode;
|
|
216
|
+
const removedText = formatMessage(messages.couponRemovedAlert, { code: removedCode });
|
|
217
|
+
// Bold the interpolated code without baking markup into the
|
|
218
|
+
// translation string — find it in the formatted sentence.
|
|
219
|
+
const codeIndex = removedText.indexOf(removedCode);
|
|
220
|
+
return (_jsx(Alert, { variant: "success", icon: CheckCircle, dismissible: true, closeLabel: formatMessage(messages.dismiss), onClose: alacarte.clearRemovedCouponCode, className: "coupon-removed-alert", "data-testid": "coupon-removed-alert", children: codeIndex === -1 ? removedText : (_jsxs(_Fragment, { children: [removedText.slice(0, codeIndex), _jsx("strong", { children: removedCode }), removedText.slice(codeIndex + removedCode.length)] })) }));
|
|
221
|
+
})(), _jsx(PaymentForm, { billing: c.billing, setField: c.setField, numberMountRef: c.numberMountRef, expiryMountRef: c.expiryMountRef, cvcMountRef: c.cvcMountRef, cardError: c.cardError, cardFieldStates: c.cardFieldStates, stripeReady: c.stripeReady, sessionReady: c.sessionReady, submitting: isAlacarteReady
|
|
215
222
|
? (alacarte.placingOrder || alacarte.awaitingPlacedOrder)
|
|
216
223
|
: c.processingSubscription, onPlaceOrder: isAlacarteReady
|
|
217
224
|
? () => {
|
|
@@ -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({ apiUrl: props.apiUrl, edxSessionUrl: props.edxSessionUrl });\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 code: appliedCouponCode,\n percent: appliedDiscount.percent,\n })}\n </Alert>\n )}\n <PaymentForm\n billing={c.billing}\n setField={c.setField}\n numberMountRef={c.numberMountRef}\n expiryMountRef={c.expiryMountRef}\n cvcMountRef={c.cvcMountRef}\n cardError={c.cardError}\n 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 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({ apiUrl: props.apiUrl, edxSessionUrl: props.edxSessionUrl });\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 code: appliedCouponCode,\n percent: appliedDiscount.percent,\n })}\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"]}
|
|
@@ -15,6 +15,11 @@ const messages = defineMessages({
|
|
|
15
15
|
defaultMessage: 'Coupon code {code} applied for {percent}% off!',
|
|
16
16
|
description: 'Success alert shown above payment methods after a coupon is applied',
|
|
17
17
|
},
|
|
18
|
+
couponRemovedAlert: {
|
|
19
|
+
id: 'checkout.couponRemovedAlert',
|
|
20
|
+
defaultMessage: 'Coupon code {code} was removed from your cart.',
|
|
21
|
+
description: 'Success alert shown above payment methods after a coupon is removed',
|
|
22
|
+
},
|
|
18
23
|
dismiss: {
|
|
19
24
|
id: 'checkout.couponAppliedAlert.dismiss',
|
|
20
25
|
defaultMessage: 'Dismiss',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/Checkout/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,4BAA4B,EAAE;QAC5B,EAAE,EAAE,mDAAmD;QACvD,cAAc,EAAE,oFAAoF;QACpG,WAAW,EAAE,gCAAgC;KAC9C;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,sCAAsC;QAC1C,cAAc,EAAE,0FAA0F;QAC1G,WAAW,EAAE,2FAA2F;KACzG;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,gDAAgD;QAChE,WAAW,EAAE,qEAAqE;KACnF;IACD,OAAO,EAAE;QACP,EAAE,EAAE,qCAAqC;QACzC,cAAc,EAAE,SAAS;QACzB,WAAW,EAAE,yCAAyC;KACvD;IACD,gBAAgB,EAAE;QAChB,EAAE,EAAE,2BAA2B;QAC/B,cAAc,EAAE,wDAAwD;QACxE,WAAW,EAAE,mEAAmE;KACjF;IACD,iBAAiB,EAAE;QACjB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,sEAAsE;QACtF,WAAW,EAAE,sDAAsD;KACpE;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,8BAA8B;QAClC,cAAc,EAAE,uEAAuE;QACvF,WAAW,EAAE,uDAAuD;KACrE;IACD,gBAAgB,EAAE;QAChB,EAAE,EAAE,uCAAuC;QAC3C,cAAc,EAAE,oBAAoB;QACpC,WAAW,EAAE,iDAAiD;KAC/D;IACD,UAAU,EAAE;QACV,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,cAAc;QAC9B,WAAW,EAAE,4DAA4D;KAC1E;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n paymentProcessingDescription: {\n id: 'checkout.paymentForm.paymentProcessingdescription',\n defaultMessage: 'Your payment could not be processed. Please check your card details and try again.',\n description: 'Payment processing description',\n },\n priceChangedNotice: {\n id: 'checkout.alacarte.priceChangedNotice',\n defaultMessage: 'The price is now ${amount} {currency}. Click Pay now to accept this amount and continue.',\n description: 'Shown when checkout.priceAccepted is false so the learner confirms the current amount due',\n },\n couponAppliedAlert: {\n id: 'checkout.couponAppliedAlert',\n defaultMessage: 'Coupon code {code} applied for {percent}% off!',\n description: 'Success alert shown above payment methods after a coupon is applied',\n },\n dismiss: {\n id: 'checkout.couponAppliedAlert.dismiss',\n defaultMessage: 'Dismiss',\n description: 'Closes the coupon-applied success alert',\n },\n validationBanner: {\n id: 'checkout.validationBanner',\n defaultMessage: 'Please complete the required fields highlighted below.',\n description: 'Error banner shown when required payment fields are not filled in',\n },\n alreadyPaidCourse: {\n id: 'checkout.alreadyPaid.course',\n defaultMessage: \"You've already paid for this course. You haven't been charged again.\",\n description: 'Alert shown when the learner already owns the course',\n },\n alreadyPaidProgram: {\n id: 'checkout.alreadyPaid.program',\n defaultMessage: \"You've already paid for this program. You haven't been charged again.\",\n description: 'Alert shown when the learner already owns the program',\n },\n viewOrderHistory: {\n id: 'checkout.alreadyPaid.viewOrderHistory',\n defaultMessage: 'View order history',\n description: 'Link to order history on the already-paid alert',\n },\n goToCourse: {\n id: 'checkout.alreadyPaid.goToCourse',\n defaultMessage: 'Go to course',\n description: 'Button to navigate to the course on the already-paid alert',\n },\n});\n\nexport default messages;\n"]}
|
|
1
|
+
{"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/Checkout/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,4BAA4B,EAAE;QAC5B,EAAE,EAAE,mDAAmD;QACvD,cAAc,EAAE,oFAAoF;QACpG,WAAW,EAAE,gCAAgC;KAC9C;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,sCAAsC;QAC1C,cAAc,EAAE,0FAA0F;QAC1G,WAAW,EAAE,2FAA2F;KACzG;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,gDAAgD;QAChE,WAAW,EAAE,qEAAqE;KACnF;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,gDAAgD;QAChE,WAAW,EAAE,qEAAqE;KACnF;IACD,OAAO,EAAE;QACP,EAAE,EAAE,qCAAqC;QACzC,cAAc,EAAE,SAAS;QACzB,WAAW,EAAE,yCAAyC;KACvD;IACD,gBAAgB,EAAE;QAChB,EAAE,EAAE,2BAA2B;QAC/B,cAAc,EAAE,wDAAwD;QACxE,WAAW,EAAE,mEAAmE;KACjF;IACD,iBAAiB,EAAE;QACjB,EAAE,EAAE,6BAA6B;QACjC,cAAc,EAAE,sEAAsE;QACtF,WAAW,EAAE,sDAAsD;KACpE;IACD,kBAAkB,EAAE;QAClB,EAAE,EAAE,8BAA8B;QAClC,cAAc,EAAE,uEAAuE;QACvF,WAAW,EAAE,uDAAuD;KACrE;IACD,gBAAgB,EAAE;QAChB,EAAE,EAAE,uCAAuC;QAC3C,cAAc,EAAE,oBAAoB;QACpC,WAAW,EAAE,iDAAiD;KAC/D;IACD,UAAU,EAAE;QACV,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,cAAc;QAC9B,WAAW,EAAE,4DAA4D;KAC1E;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n paymentProcessingDescription: {\n id: 'checkout.paymentForm.paymentProcessingdescription',\n defaultMessage: 'Your payment could not be processed. Please check your card details and try again.',\n description: 'Payment processing description',\n },\n priceChangedNotice: {\n id: 'checkout.alacarte.priceChangedNotice',\n defaultMessage: 'The price is now ${amount} {currency}. Click Pay now to accept this amount and continue.',\n description: 'Shown when checkout.priceAccepted is false so the learner confirms the current amount due',\n },\n couponAppliedAlert: {\n id: 'checkout.couponAppliedAlert',\n defaultMessage: 'Coupon code {code} applied for {percent}% off!',\n description: 'Success alert shown above payment methods after a coupon is applied',\n },\n couponRemovedAlert: {\n id: 'checkout.couponRemovedAlert',\n defaultMessage: 'Coupon code {code} was removed from your cart.',\n description: 'Success alert shown above payment methods after a coupon is removed',\n },\n dismiss: {\n id: 'checkout.couponAppliedAlert.dismiss',\n defaultMessage: 'Dismiss',\n description: 'Closes the coupon-applied success alert',\n },\n validationBanner: {\n id: 'checkout.validationBanner',\n defaultMessage: 'Please complete the required fields highlighted below.',\n description: 'Error banner shown when required payment fields are not filled in',\n },\n alreadyPaidCourse: {\n id: 'checkout.alreadyPaid.course',\n defaultMessage: \"You've already paid for this course. You haven't been charged again.\",\n description: 'Alert shown when the learner already owns the course',\n },\n alreadyPaidProgram: {\n id: 'checkout.alreadyPaid.program',\n defaultMessage: \"You've already paid for this program. You haven't been charged again.\",\n description: 'Alert shown when the learner already owns the program',\n },\n viewOrderHistory: {\n id: 'checkout.alreadyPaid.viewOrderHistory',\n defaultMessage: 'View order history',\n description: 'Link to order history on the already-paid alert',\n },\n goToCourse: {\n id: 'checkout.alreadyPaid.goToCourse',\n defaultMessage: 'Go to course',\n description: 'Button to navigate to the course on the already-paid alert',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -26,6 +26,10 @@ export interface UseAlacarteCheckoutResult extends AlacartePhaseState {
|
|
|
26
26
|
applyCoupon: (code: string) => void;
|
|
27
27
|
removeCoupon: () => void;
|
|
28
28
|
clearCouponError: () => void;
|
|
29
|
+
/** Code of the coupon just removed, set only once the removal round-trip
|
|
30
|
+
* completes — kept in sync with when the discount actually leaves the line. */
|
|
31
|
+
removedCouponCode: string | null;
|
|
32
|
+
clearRemovedCouponCode: () => void;
|
|
29
33
|
placingOrder: boolean;
|
|
30
34
|
placeOrderError: string | null;
|
|
31
35
|
/**
|
|
@@ -300,6 +300,7 @@ export function useAlacarteCheckout(options) {
|
|
|
300
300
|
}, [createdCheckout, discountCode, couponIsIdle, couponMutate]);
|
|
301
301
|
const [checkoutOverride, setCheckoutOverride] = useState(null);
|
|
302
302
|
const [couponError, setCouponError] = useState(null);
|
|
303
|
+
const [removedCouponCode, setRemovedCouponCode] = useState(null);
|
|
303
304
|
const [placeOrderError, setPlaceOrderError] = useState(null);
|
|
304
305
|
const [placingOrder, setPlacingOrder] = useState(false);
|
|
305
306
|
// biId of a checkout that's locked (CART_PAYMENT_PENDING) from a prior
|
|
@@ -312,6 +313,7 @@ export function useAlacarteCheckout(options) {
|
|
|
312
313
|
useEffect(() => {
|
|
313
314
|
setCheckoutOverride(null);
|
|
314
315
|
setCouponError(null);
|
|
316
|
+
setRemovedCouponCode(null);
|
|
315
317
|
setPlaceOrderError(null);
|
|
316
318
|
setCardRetryBiId(null);
|
|
317
319
|
selectReset();
|
|
@@ -339,7 +341,7 @@ export function useAlacarteCheckout(options) {
|
|
|
339
341
|
}
|
|
340
342
|
const result = urlCouponMutation.data;
|
|
341
343
|
if (result && !result.ok) {
|
|
342
|
-
setCouponError(getCouponErrorMessage(result.error));
|
|
344
|
+
setCouponError(getCouponErrorMessage(result.error, discountCode));
|
|
343
345
|
}
|
|
344
346
|
}, [
|
|
345
347
|
discountCode,
|
|
@@ -408,9 +410,10 @@ export function useAlacarteCheckout(options) {
|
|
|
408
410
|
if (result.ok && result.checkout) {
|
|
409
411
|
setCheckoutOverride(result.checkout);
|
|
410
412
|
setCouponError(null);
|
|
413
|
+
setRemovedCouponCode(null);
|
|
411
414
|
}
|
|
412
415
|
else {
|
|
413
|
-
setCouponError(getCouponErrorMessage(result.error));
|
|
416
|
+
setCouponError(getCouponErrorMessage(result.error, trimmed));
|
|
414
417
|
}
|
|
415
418
|
},
|
|
416
419
|
onError: (err) => {
|
|
@@ -419,9 +422,11 @@ export function useAlacarteCheckout(options) {
|
|
|
419
422
|
});
|
|
420
423
|
}, [(_j = derived.checkout) === null || _j === void 0 ? void 0 : _j.biId, client, manualUpdateMutation]);
|
|
421
424
|
const removeCoupon = useCallback(() => {
|
|
425
|
+
var _a;
|
|
422
426
|
const currentCheckout = derived.checkout;
|
|
423
427
|
if (!(currentCheckout === null || currentCheckout === void 0 ? void 0 : currentCheckout.biId) || !client)
|
|
424
428
|
return;
|
|
429
|
+
const removedCode = ((_a = currentCheckout.couponCode) === null || _a === void 0 ? void 0 : _a.trim()) || null;
|
|
425
430
|
setCouponError(null);
|
|
426
431
|
manualUpdateMutation.mutate({ biId: currentCheckout.biId, couponCode: '' }, {
|
|
427
432
|
onSuccess: (result) => {
|
|
@@ -442,6 +447,8 @@ export function useAlacarteCheckout(options) {
|
|
|
442
447
|
: null;
|
|
443
448
|
setCheckoutOverride(Object.assign(Object.assign({}, base), { couponCode: null, line: patchedLine }));
|
|
444
449
|
setCouponError(null);
|
|
450
|
+
if (removedCode)
|
|
451
|
+
setRemovedCouponCode(removedCode);
|
|
445
452
|
},
|
|
446
453
|
onError: (err) => {
|
|
447
454
|
setCouponError(errorMessage(err));
|
|
@@ -510,7 +517,7 @@ export function useAlacarteCheckout(options) {
|
|
|
510
517
|
return null;
|
|
511
518
|
})();
|
|
512
519
|
return Object.assign(Object.assign({}, derived), { couponError, couponApplying: manualUpdateMutation.isPending, applyCoupon,
|
|
513
|
-
removeCoupon, clearCouponError: () => setCouponError(null), placingOrder,
|
|
520
|
+
removeCoupon, clearCouponError: () => setCouponError(null), removedCouponCode, clearRemovedCouponCode: () => setRemovedCouponCode(null), placingOrder,
|
|
514
521
|
placeOrderError,
|
|
515
522
|
placeOrder, placeOrderAsync: placeOrderCore, clearPlaceOrderError: () => setPlaceOrderError(null), paymentDecline: (_q = (_p = derived.checkout) === null || _p === void 0 ? void 0 : _p.paymentDecline) !== null && _q !== void 0 ? _q : null, placedOrder, awaitingPlacedOrder: !!orderBiId && !placedOrder && !placedOrderError && (placedOrderQuery.isLoading
|
|
516
523
|
|| placedOrderQuery.isFetching
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAlacarteCheckout.js","sourceRoot":"","sources":["../../../src/data/hooks/useAlacarteCheckout.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * data/hooks/useAlacarteCheckout.ts — page-level orchestration for the à la\n * carte checkout flow:\n *\n * 1. Read a product selector (course or program) from the URL via nuqs.\n * 2. If a product is selected: check ownership (tOwnedProducts). Already\n * owned -> 'alreadyOwned'. Otherwise select it into the checkout\n * (tCheckoutSelect) and fetch its display details in parallel.\n * 3. If no product is selected: look for an existing open checkout\n * (tCheckout). Found -> 'ready'. Not found -> 'noActiveCheckout'.\n * 4. Coupon apply/remove and payment prep via tCheckoutUpdate.\n *\n * See /alacarte-checkout-api.md and /alacarte-owned-products-api.md at the\n * repo root for the underlying API contract.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useQueryStates, useQueryState, parseAsString } from 'nuqs';\nimport { createAlacarteCheckoutClient } from '../../utils/alacarteCheckout';\nimport { getCouponErrorMessage, getCouponRecheckMessage } from '../../utils/couponErrors';\nimport {\n placeAlacarteOrder,\n toAlacarteBillingAddress,\n} from '../../utils/alacartePayment';\nimport { AlacartePlaceOrderError } from '../../utils/placeOrderErrors';\nimport { CardValidationError } from '../../utils/stripeCard';\nimport { useViaxSessionQuery } from './useCheckoutQueries';\nimport {\n useOwnedProductQuery, useAlacarteCheckoutQuery, useSelectProductMutation, useProductDetailQuery,\n useUpdateCheckoutMutation, usePlacedOrderQuery, useOrderDatesQuery,\n} from './useAlacarteQueries';\nimport type {\n AlacarteCheckout, AlacarteCheckoutResult, AlacarteLine, AlacarteMoney, AlacartePaymentDecline,\n AlacartePriceChanged, OwnedProduct, OwnedProductResult, PlacedOrder, ProductDetail, ProductSelector,\n} from '../../types/alacarte';\nimport type { BillingInfo } from '../../types';\n\nexport type AlacartePhase = 'loading' | 'alreadyOwned' | 'noActiveCheckout' | 'notPurchasable' | 'ready' | 'error';\n\nexport type AlacarteNoticeMessageId = 'alreadyOwnedCourse' | 'alreadyOwnedProgram' | 'noActiveCheckout';\n\n/** Pure phase decision output — no action callbacks. */\nexport interface AlacartePhaseState {\n phase: AlacartePhase,\n noticeMessageId?: AlacarteNoticeMessageId,\n selector: ProductSelector,\n checkout: AlacarteCheckout | null,\n line: AlacarteLine | null,\n productDetail: ProductDetail | null,\n error: string | null,\n priceChanged: AlacartePriceChanged | null,\n priceAccepted: boolean,\n /** True when the learner already owns this product. The checkout data may\n * still be populated so the UI can render the full page under an overlay. */\n isAlreadyOwned: boolean,\n /** Product name from the owned-products query — used as a fallback when the\n * checkout line (which normally carries the name) is not available. */\n ownedProductName: string | null,\n}\n\nexport interface UseAlacarteCheckoutResult extends AlacartePhaseState {\n couponError: string | null,\n couponApplying: boolean,\n applyCoupon: (code: string) => void,\n removeCoupon: () => void,\n clearCouponError: () => void,\n placingOrder: boolean,\n placeOrderError: string | null,\n /**\n * Accepts price (if needed) + terms, calls tCheckoutPlaceOrder with billing,\n * confirms the card via Stripe.js, then sets ?order_bi_id= to poll tPlacedOrder.\n * Fire-and-forget — errors go to placeOrderError state.\n */\n placeOrder: (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => void,\n /**\n * Same as placeOrder but returns a Promise — used by ExpressCheckout\n * so the wallet sheet can await the result and call ev.complete().\n */\n placeOrderAsync: (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => Promise<void>,\n clearPlaceOrderError: () => void,\n /** Decline details from the last card attempt on this checkout, if any. */\n paymentDecline: AlacartePaymentDecline | null,\n /** When ?order_bi_id= is present, the placed order (or null while polling). */\n placedOrder: PlacedOrder | null,\n awaitingPlacedOrder: boolean,\n placedOrderError: string | null,\n /** ISO timestamp the order was placed (tPlacedAt, falling back to\n * biCreatedAt); null while the order-dates query hasn't resolved yet. */\n placedOrderPlacedAt: string | null,\n}\n\n/**\n * Read the product selector from the URL: course_uid+course_run_key, or\n * program_uid, or neither. Both course params must be present together; if a\n * course param and a program param are both present, that's\n * CONFLICTING_SELECTION.\n *\n * NOTE: course_run_key values look like \"course-v1:HarvardX+CS50+X\" — nuqs\n * decodes query values the standards-compliant way (literal `+` -> space),\n * same as native URLSearchParams. This assumes whoever generates links into\n * this page percent-encodes `+` as %2B. Verify this in practice; see the plan\n * doc for the fallback if it's ever violated (drop nuqs for course_run_key\n * specifically).\n */\nexport function useProductSelector(): ProductSelector {\n const [{ courseUid, runKey, programUid }] = useQueryStates({\n courseUid: parseAsString,\n runKey: parseAsString,\n programUid: parseAsString,\n }, {\n urlKeys: {\n courseUid: 'course_uid',\n runKey: 'course_run_key',\n programUid: 'program_uid',\n },\n });\n\n return useMemo<ProductSelector>(() => {\n const hasCourse = !!courseUid || !!runKey;\n const hasProgram = !!programUid;\n if (hasCourse && hasProgram) return { kind: 'invalid' };\n if (courseUid && runKey) return { kind: 'course', courseUid, runKey };\n if (programUid) return { kind: 'program', programUid };\n return { kind: 'none' };\n }, [courseUid, runKey, programUid]);\n}\n\n/** Reads ?discount_code= — applied to the checkout right after it's created. */\nexport function useDiscountCode(): string | null {\n const [discountCode] = useQueryState('discount_code', parseAsString);\n return discountCode;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'Unknown error';\n}\n\n/**\n * Build a synthetic AlacarteLine from the owned-product pricing data so the\n * checkout overlay can show subtotal / deduction / total even when the backend\n * blocks tCheckoutSelect and returns no checkout object.\n */\nfunction buildLineFromOwnedProduct(product: OwnedProduct): AlacarteLine | null {\n if (!product.price) return null;\n const { full, deduction, amountDue, currency } = product.price;\n const toMoney = (amount: number): AlacarteMoney => ({ amount, currency });\n\n if (product.kind === 'program') {\n return {\n biiId: '',\n kind: 'program',\n programId: product.productId,\n programName: product.name,\n price: toMoney(full),\n deduction: deduction ? toMoney(deduction) : null,\n ownedCourses: product.ownedCourses.map((c) => ({\n courseId: c.courseId, name: c.name, via: c.via,\n })),\n discount: null,\n amountDue: toMoney(amountDue),\n billingAddressSet: false,\n };\n }\n\n return {\n biiId: '',\n kind: 'course',\n courseName: product.name,\n courseUid: product.productId,\n courseRunKey: '',\n seatType: 'verified',\n price: toMoney(full),\n discount: null,\n amountDue: toMoney(amountDue),\n billingAddressSet: false,\n };\n}\n\ninterface QueryLikeState<T> {\n isLoading: boolean,\n isError: boolean,\n error?: unknown,\n data?: T,\n}\n\ninterface MutationLikeState<T> {\n isIdle: boolean,\n isPending: boolean,\n isError: boolean,\n error?: unknown,\n data?: T,\n}\n\nexport interface DeriveAlacartePhaseInput {\n selector: ProductSelector,\n sessionReady: boolean,\n sessionIsError: boolean,\n sessionErrorMessage?: string,\n ownedQuery: QueryLikeState<OwnedProductResult>,\n selectMutation: MutationLikeState<AlacarteCheckoutResult>,\n checkoutQuery: QueryLikeState<AlacarteCheckoutResult>,\n productDetail: ProductDetail | null,\n /** Coupon (?discount_code=) applied right after the checkout is created —\n * when it succeeds, its checkout (with the coupon's discount reflected)\n * is shown in place of the pre-coupon one from selectMutation. */\n couponMutation?: MutationLikeState<AlacarteCheckoutResult>,\n /** True when a URL discount code still needs to be applied — the phase\n * stays 'loading' until the coupon mutation resolves so the user never sees\n * the pre-discount price flash. */\n urlCouponPending?: boolean,\n /** Latest successful manual update (coupon / acceptPrice / terms). Wins over\n * select + URL coupon when present. */\n checkoutOverride?: AlacarteCheckout | null,\n}\n\n/**\n * Pure decision function — no hooks, no React Query/nuqs types beyond plain\n * data — so every branch combination can be unit-tested directly.\n */\nexport function deriveAlacartePhase(input: DeriveAlacartePhaseInput): AlacartePhaseState {\n const {\n selector, sessionReady, sessionIsError, sessionErrorMessage,\n ownedQuery, selectMutation, checkoutQuery, productDetail, couponMutation,\n checkoutOverride = null, urlCouponPending: urlCouponPendingProp = false,\n } = input;\n\n const ownedProductName = ownedQuery.data?.product?.name ?? null;\n\n const empty: Omit<AlacartePhaseState, 'phase'> = {\n selector,\n checkout: null,\n line: null,\n productDetail: null,\n error: null,\n priceChanged: null,\n priceAccepted: false,\n isAlreadyOwned: false,\n ownedProductName: null,\n };\n\n const withCheckout = (\n checkout: AlacarteCheckout | null,\n priceChanged: AlacartePriceChanged | null = null,\n isAlreadyOwned = false,\n ): AlacartePhaseState => ({\n phase: isAlreadyOwned ? 'alreadyOwned' : 'ready',\n selector,\n checkout,\n line: checkout?.line ?? null,\n productDetail,\n error: null,\n priceChanged: priceChanged ?? null,\n priceAccepted: checkout?.priceAccepted === true,\n isAlreadyOwned,\n ownedProductName: isAlreadyOwned ? ownedProductName : null,\n });\n\n if (selector.kind === 'invalid') {\n return { phase: 'error', ...empty, error: 'CONFLICTING_SELECTION' };\n }\n if (sessionIsError) {\n return { phase: 'error', ...empty, error: sessionErrorMessage ?? 'Session error' };\n }\n\n const hasSelector = selector.kind === 'course' || selector.kind === 'program';\n\n if (hasSelector) {\n if (!sessionReady || ownedQuery.isLoading) {\n return { phase: 'loading', ...empty };\n }\n if (ownedQuery.isError) {\n return { phase: 'error', ...empty, error: errorMessage(ownedQuery.error) };\n }\n\n const isOwned = ownedQuery.data?.ok === true && ownedQuery.data.product?.status === 'full';\n\n if (selectMutation.isIdle || selectMutation.isPending) {\n return { phase: 'loading', ...empty };\n }\n if (selectMutation.isError) {\n return { phase: 'error', ...empty, error: errorMessage(selectMutation.error) };\n }\n if (selectMutation.data && !selectMutation.data.ok) {\n // The backend may block ALREADY_OWNED at select time. When the\n // blocked response still includes checkout data (line, pricing), use\n // it so the overlay page shows the real totals. Fall back to the\n // standalone tCheckout query, then to an empty state.\n if (selectMutation.data.blocked?.reason === 'ALREADY_OWNED') {\n const blockedCheckout = selectMutation.data.checkout\n ?? (checkoutQuery.data?.ok ? checkoutQuery.data.checkout : null);\n if (blockedCheckout) {\n return withCheckout(blockedCheckout, selectMutation.data.priceChanged ?? null, true);\n }\n // Build a synthetic line from the owned-product pricing so the\n // overlay can show subtotal / deduction / total.\n const ownedProduct = ownedQuery.data?.product;\n const syntheticLine = ownedProduct ? buildLineFromOwnedProduct(ownedProduct) : null;\n return {\n phase: 'alreadyOwned',\n noticeMessageId: selectMutation.data.blocked.kind === 'course' ? 'alreadyOwnedCourse' : 'alreadyOwnedProgram',\n ...empty,\n line: syntheticLine,\n productDetail,\n isAlreadyOwned: true,\n ownedProductName,\n };\n }\n if (selectMutation.data.blocked?.reason === 'NOT_PURCHASABLE') {\n return {\n phase: 'notPurchasable',\n ...empty,\n productDetail,\n error: selectMutation.data.blocked.kind === 'program'\n ? 'This program is not eligible for checkout.'\n : 'This course is not eligible for checkout.',\n };\n }\n const selectError = selectMutation.data.error;\n if (selectError === 'COURSE_NOT_FOUND' || selectError === 'PRODUCT_NOT_FOUND') {\n return {\n phase: 'error',\n ...empty,\n error: 'This course could not be found.',\n };\n }\n if (selectError === 'PROGRAM_NOT_FOUND') {\n return {\n phase: 'error',\n ...empty,\n error: 'This program could not be found.',\n };\n }\n const blockedDetail = selectMutation.data.blocked?.detail;\n return {\n phase: 'error',\n ...empty,\n error: blockedDetail ?? selectError ?? 'unknown',\n };\n }\n\n // When a URL discount code still needs to be applied, stay in 'loading'\n // so the user never sees the pre-discount price flash.\n if (urlCouponPendingProp && !checkoutOverride) {\n return { phase: 'loading', ...empty };\n }\n\n // Once the coupon-apply (?discount_code=) mutation succeeds, its checkout\n // (with the discount reflected) supersedes the pre-coupon one. Manual\n // updates (override) win over both.\n const finalCheckout = checkoutOverride\n ?? (couponMutation?.data?.ok\n ? couponMutation.data.checkout\n : selectMutation.data?.checkout ?? null);\n\n // When select succeeds but the owned-products query says the learner\n // already has this product, show the full checkout under an overlay.\n return withCheckout(\n finalCheckout,\n selectMutation.data?.priceChanged\n ?? (couponMutation?.data?.ok ? couponMutation.data.priceChanged : undefined)\n ?? null,\n isOwned,\n );\n }\n\n // No selector: fall back to the learner's existing open checkout, if any.\n if (!sessionReady || checkoutQuery.isLoading) {\n return { phase: 'loading', ...empty };\n }\n if (checkoutQuery.isError) {\n return { phase: 'error', ...empty, error: errorMessage(checkoutQuery.error) };\n }\n if (checkoutOverride || checkoutQuery.data?.checkout) {\n const checkout = checkoutOverride ?? checkoutQuery.data!.checkout;\n return withCheckout(checkout, checkoutQuery.data?.priceChanged ?? null);\n }\n\n return { phase: 'noActiveCheckout', noticeMessageId: 'noActiveCheckout', ...empty, isAlreadyOwned: false, ownedProductName: null };\n}\n\nexport function useAlacarteCheckout(\n options: { apiUrl?: string, edxSessionUrl?: string },\n): UseAlacarteCheckoutResult {\n const { apiUrl, edxSessionUrl } = options;\n const selector = useProductSelector();\n const discountCode = useDiscountCode();\n const [orderBiId, setOrderBiId] = useQueryState('order_bi_id', parseAsString);\n\n const client = useMemo(\n () => (apiUrl ? createAlacarteCheckoutClient({ apiUrl }) : null),\n [apiUrl],\n );\n\n // Reuses the same query key as useCheckout's session exchange — React\n // Query dedupes the network call regardless of how many hooks read it.\n const sessionQuery = useViaxSessionQuery(edxSessionUrl ?? null);\n const sessionReady = !!sessionQuery.data;\n\n useEffect(() => {\n if (sessionQuery.data && client) {\n client.setToken(sessionQuery.data.viaxToken);\n }\n }, [sessionQuery.data, client]);\n\n const hasSelector = selector.kind === 'course' || selector.kind === 'program';\n const productId = selector.kind === 'course'\n ? selector.courseUid\n : selector.kind === 'program' ? selector.programUid : null;\n\n const ownedQuery = useOwnedProductQuery(client, sessionReady && hasSelector, productId);\n const isOwned = ownedQuery.data?.ok === true && ownedQuery.data.product?.status === 'full';\n\n const selectMutation = useSelectProductMutation(client);\n const {\n isIdle: selectIsIdle, mutate: selectMutate, reset: selectReset,\n } = selectMutation;\n\n // Mutations aren't called during render — fire once the owned-products\n // query resolves (regardless of result) so we always get checkout/line data.\n // Pass viewedPrice from tOwnedProducts.amountDue (ALC-159) when available.\n useEffect(() => {\n if (!hasSelector || ownedQuery.isLoading || ownedQuery.isError) return;\n if (!selectIsIdle) return;\n const amountDue = ownedQuery.data?.product?.price?.amountDue;\n selectMutate({\n selector,\n viewedPrice: typeof amountDue === 'number' ? amountDue : undefined,\n });\n }, [\n hasSelector,\n ownedQuery.isLoading,\n ownedQuery.isError,\n ownedQuery.data?.product?.price?.amountDue,\n selector,\n selectIsIdle,\n selectMutate,\n ]);\n\n const productDetailEnabled = hasSelector && sessionReady && !ownedQuery.isLoading;\n const productDetailQuery = useProductDetailQuery(client, productDetailEnabled, selector);\n\n // Run the checkout query when there's no selector (standard path) OR when\n // the product is already owned — after the select mutation is blocked with\n // ALREADY_OWNED the server may still have an open checkout with pricing data.\n const selectBlocked = !selectMutation.isIdle && !selectMutation.isPending\n && selectMutation.data && !selectMutation.data.ok;\n const checkoutQuery = useAlacarteCheckoutQuery(\n client,\n sessionReady && (!hasSelector || (isOwned && !!selectBlocked)),\n );\n\n // Apply ?discount_code= to the freshly-created checkout — fired once the\n // select mutation succeeds with a checkout that doesn't already carry it.\n const urlCouponMutation = useUpdateCheckoutMutation(client);\n const {\n isIdle: couponIsIdle, mutate: couponMutate, reset: urlCouponReset,\n } = urlCouponMutation;\n const createdCheckout = selectMutation.data?.ok ? selectMutation.data.checkout : null;\n\n useEffect(() => {\n if (!createdCheckout || !discountCode) return;\n if (createdCheckout.couponCode === discountCode) return;\n if (couponIsIdle) {\n couponMutate({ biId: createdCheckout.biId, couponCode: discountCode });\n }\n }, [createdCheckout, discountCode, couponIsIdle, couponMutate]);\n\n const [checkoutOverride, setCheckoutOverride] = useState<AlacarteCheckout | null>(null);\n const [couponError, setCouponError] = useState<string | null>(null);\n const [placeOrderError, setPlaceOrderError] = useState<string | null>(null);\n const [placingOrder, setPlacingOrder] = useState(false);\n // biId of a checkout that's locked (CART_PAYMENT_PENDING) from a prior\n // tCheckoutPlaceOrder call whose Stripe confirmation was rejected\n // client-side. The next attempt must skip tCheckoutUpdate (it would fail\n // with CHECKOUT_NOT_OPEN) and go straight to tCheckoutPlaceOrder again.\n const [cardRetryBiId, setCardRetryBiId] = useState<string | null>(null);\n\n // Reset local overrides and in-flight select/coupon when the product changes\n // so viewedPrice / couponRecheck run again for the new selection.\n useEffect(() => {\n setCheckoutOverride(null);\n setCouponError(null);\n setPlaceOrderError(null);\n setCardRetryBiId(null);\n selectReset();\n urlCouponReset();\n }, [selector, selectReset, urlCouponReset]);\n\n // Surface couponRecheck from product switch (section 2 of the API doc).\n useEffect(() => {\n const result = selectMutation.data;\n if (!result?.ok) return;\n const message = getCouponRecheckMessage(\n result.couponRecheck,\n result.checkout?.line?.discountSource,\n );\n if (message) setCouponError(message);\n }, [selectMutation.data]);\n\n // Surface ?discount_code= apply failures (domain ok:false or transport error).\n useEffect(() => {\n if (!discountCode) return;\n if (urlCouponMutation.isIdle || urlCouponMutation.isPending) return;\n if (urlCouponMutation.isError) {\n setCouponError(errorMessage(urlCouponMutation.error));\n return;\n }\n const result = urlCouponMutation.data;\n if (result && !result.ok) {\n setCouponError(getCouponErrorMessage(result.error));\n }\n }, [\n discountCode,\n urlCouponMutation.isIdle,\n urlCouponMutation.isPending,\n urlCouponMutation.isError,\n urlCouponMutation.error,\n urlCouponMutation.data,\n ]);\n\n const manualUpdateMutation = useUpdateCheckoutMutation(client);\n\n const placedOrderQuery = usePlacedOrderQuery(\n client,\n orderBiId,\n sessionReady && !!orderBiId,\n );\n\n const orderDatesQuery = useOrderDatesQuery(\n client,\n orderBiId,\n sessionReady && !!orderBiId,\n );\n\n const derived = deriveAlacartePhase({\n selector,\n sessionReady,\n sessionIsError: sessionQuery.isError,\n sessionErrorMessage: sessionQuery.error?.message,\n ownedQuery: {\n isLoading: ownedQuery.isLoading,\n isError: ownedQuery.isError,\n error: ownedQuery.error,\n data: ownedQuery.data,\n },\n selectMutation: {\n isIdle: selectMutation.isIdle,\n isPending: selectMutation.isPending,\n isError: selectMutation.isError,\n error: selectMutation.error,\n data: selectMutation.data,\n },\n checkoutQuery: {\n isLoading: checkoutQuery.isLoading,\n isError: checkoutQuery.isError,\n error: checkoutQuery.error,\n data: checkoutQuery.data,\n },\n productDetail: productDetailQuery.data ?? null,\n couponMutation: {\n isIdle: urlCouponMutation.isIdle,\n isPending: urlCouponMutation.isPending,\n isError: urlCouponMutation.isError,\n error: urlCouponMutation.error,\n data: urlCouponMutation.data,\n },\n checkoutOverride,\n // The URL coupon is pending only when the checkout exists, doesn't already\n // carry the code, and the mutation hasn't completed yet. When the backend\n // returns the coupon pre-applied (couponCode === discountCode) or when\n // there's no discount_code param at all, this is false from the start.\n urlCouponPending: !!discountCode\n && !!createdCheckout\n && createdCheckout.couponCode !== discountCode\n && (urlCouponMutation.isIdle || urlCouponMutation.isPending),\n });\n\n const applyCoupon = useCallback((code: string) => {\n const biId = derived.checkout?.biId;\n if (!biId || !client) return;\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCouponError(null);\n manualUpdateMutation.mutate(\n { biId, couponCode: trimmed },\n {\n onSuccess: (result) => {\n if (result.ok && result.checkout) {\n setCheckoutOverride(result.checkout);\n setCouponError(null);\n } else {\n setCouponError(getCouponErrorMessage(result.error));\n }\n },\n onError: (err) => {\n setCouponError(errorMessage(err));\n },\n },\n );\n }, [derived.checkout?.biId, client, manualUpdateMutation]);\n\n const removeCoupon = useCallback(() => {\n const currentCheckout = derived.checkout;\n if (!currentCheckout?.biId || !client) return;\n\n setCouponError(null);\n manualUpdateMutation.mutate(\n { biId: currentCheckout.biId, couponCode: '' },\n {\n onSuccess: (result) => {\n if (!result.ok) {\n setCouponError(getCouponErrorMessage(result.error));\n return;\n }\n // The backend may return a checkout whose line still carries the\n // old discount/amountDue. Always patch the line to clear the\n // coupon so the cart summary reflects the removal immediately.\n const base = result.checkout ?? currentCheckout;\n const line = base.line;\n const patchedLine = line\n ? {\n ...line,\n discount: null,\n amountDue: line.price && line.kind === 'program' && 'deduction' in line && line.deduction\n ? { amount: line.price.amount - line.deduction.amount, currency: line.price.currency }\n : line.price,\n } as typeof line\n : null;\n setCheckoutOverride({\n ...base,\n couponCode: null,\n line: patchedLine,\n });\n setCouponError(null);\n },\n onError: (err) => {\n setCouponError(errorMessage(err));\n },\n },\n );\n }, [derived.checkout, client, manualUpdateMutation]);\n\n const placeOrderCore = useCallback(async (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => {\n const checkout = derived.checkout;\n if (!checkout || !client) throw new Error('Checkout not ready');\n\n setPlacingOrder(true);\n setPlaceOrderError(null);\n\n try {\n const { checkout: updated } = await placeAlacarteOrder({\n updateCheckout: (args) => client.updateCheckout(args),\n placeCheckoutOrder: (biId, billing) => client.placeCheckoutOrder(biId, billing),\n checkout,\n billing: toAlacarteBillingAddress(opts.billing),\n confirmCardPayment: opts.confirmCardPayment,\n skipPrepare: cardRetryBiId === checkout.biId,\n });\n\n setCardRetryBiId(null);\n setCheckoutOverride(updated);\n await setOrderBiId(updated.biId);\n } catch (err: unknown) {\n if (err instanceof CardValidationError) {\n // tCheckoutPlaceOrder already succeeded and locked the checkout\n // (CART_PAYMENT_PENDING); Stripe rejected the card before it ever\n // reached the backend. Next attempt must retry tCheckoutPlaceOrder\n // directly, not tCheckoutUpdate.\n setCardRetryBiId(checkout.biId);\n } else {\n setCardRetryBiId(null);\n }\n if (err instanceof AlacartePlaceOrderError && err.checkout) {\n setCheckoutOverride(err.checkout);\n }\n setPlaceOrderError(errorMessage(err));\n throw err;\n } finally {\n setPlacingOrder(false);\n }\n }, [derived.checkout, client, setOrderBiId, cardRetryBiId]);\n\n /** Fire-and-forget wrapper for card payments. */\n const placeOrder = useCallback((opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => {\n if (placingOrder) return;\n placeOrderCore(opts).catch(() => { /* error already in state */ });\n }, [placeOrderCore, placingOrder]);\n\n const placedOrder = placedOrderQuery.data?.ok ? placedOrderQuery.data.order : null;\n\n const dates = orderDatesQuery.data?.ok ? orderDatesQuery.data.dates : null;\n const placedOrderPlacedAt = dates?.tPlacedAt ?? dates?.biCreatedAt ?? null;\n\n const placedOrderError = (() => {\n if (!orderBiId) return null;\n if (\n placedOrderQuery.data\n && !placedOrderQuery.data.ok\n && placedOrderQuery.data.error !== 'NOT_PLACED'\n && placedOrderQuery.data.error !== 'ORDER_READ_FAILED'\n ) {\n return placedOrderQuery.data.error ?? 'ORDER_READ_FAILED';\n }\n return null;\n })();\n\n return {\n ...derived,\n couponError,\n couponApplying: manualUpdateMutation.isPending,\n applyCoupon,\n removeCoupon,\n clearCouponError: () => setCouponError(null),\n placingOrder,\n placeOrderError,\n placeOrder,\n placeOrderAsync: placeOrderCore,\n clearPlaceOrderError: () => setPlaceOrderError(null),\n paymentDecline: derived.checkout?.paymentDecline ?? null,\n placedOrder,\n awaitingPlacedOrder: !!orderBiId && !placedOrder && !placedOrderError && (\n placedOrderQuery.isLoading\n || placedOrderQuery.isFetching\n || placedOrderQuery.data?.error === 'NOT_PLACED'\n || placedOrderQuery.data?.error === 'ORDER_READ_FAILED'\n || (placedOrderQuery.data?.ok === true && !placedOrderQuery.data.order)\n || !placedOrderQuery.data\n ),\n placedOrderError,\n placedOrderPlacedAt,\n };\n}\n\nexport default useAlacarteCheckout;\n"]}
|
|
1
|
+
{"version":3,"file":"useAlacarteCheckout.js","sourceRoot":"","sources":["../../../src/data/hooks/useAlacarteCheckout.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * data/hooks/useAlacarteCheckout.ts — page-level orchestration for the à la\n * carte checkout flow:\n *\n * 1. Read a product selector (course or program) from the URL via nuqs.\n * 2. If a product is selected: check ownership (tOwnedProducts). Already\n * owned -> 'alreadyOwned'. Otherwise select it into the checkout\n * (tCheckoutSelect) and fetch its display details in parallel.\n * 3. If no product is selected: look for an existing open checkout\n * (tCheckout). Found -> 'ready'. Not found -> 'noActiveCheckout'.\n * 4. Coupon apply/remove and payment prep via tCheckoutUpdate.\n *\n * See /alacarte-checkout-api.md and /alacarte-owned-products-api.md at the\n * repo root for the underlying API contract.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useQueryStates, useQueryState, parseAsString } from 'nuqs';\nimport { createAlacarteCheckoutClient } from '../../utils/alacarteCheckout';\nimport { getCouponErrorMessage, getCouponRecheckMessage } from '../../utils/couponErrors';\nimport {\n placeAlacarteOrder,\n toAlacarteBillingAddress,\n} from '../../utils/alacartePayment';\nimport { AlacartePlaceOrderError } from '../../utils/placeOrderErrors';\nimport { CardValidationError } from '../../utils/stripeCard';\nimport { useViaxSessionQuery } from './useCheckoutQueries';\nimport {\n useOwnedProductQuery, useAlacarteCheckoutQuery, useSelectProductMutation, useProductDetailQuery,\n useUpdateCheckoutMutation, usePlacedOrderQuery, useOrderDatesQuery,\n} from './useAlacarteQueries';\nimport type {\n AlacarteCheckout, AlacarteCheckoutResult, AlacarteLine, AlacarteMoney, AlacartePaymentDecline,\n AlacartePriceChanged, OwnedProduct, OwnedProductResult, PlacedOrder, ProductDetail, ProductSelector,\n} from '../../types/alacarte';\nimport type { BillingInfo } from '../../types';\n\nexport type AlacartePhase = 'loading' | 'alreadyOwned' | 'noActiveCheckout' | 'notPurchasable' | 'ready' | 'error';\n\nexport type AlacarteNoticeMessageId = 'alreadyOwnedCourse' | 'alreadyOwnedProgram' | 'noActiveCheckout';\n\n/** Pure phase decision output — no action callbacks. */\nexport interface AlacartePhaseState {\n phase: AlacartePhase,\n noticeMessageId?: AlacarteNoticeMessageId,\n selector: ProductSelector,\n checkout: AlacarteCheckout | null,\n line: AlacarteLine | null,\n productDetail: ProductDetail | null,\n error: string | null,\n priceChanged: AlacartePriceChanged | null,\n priceAccepted: boolean,\n /** True when the learner already owns this product. The checkout data may\n * still be populated so the UI can render the full page under an overlay. */\n isAlreadyOwned: boolean,\n /** Product name from the owned-products query — used as a fallback when the\n * checkout line (which normally carries the name) is not available. */\n ownedProductName: string | null,\n}\n\nexport interface UseAlacarteCheckoutResult extends AlacartePhaseState {\n couponError: string | null,\n couponApplying: boolean,\n applyCoupon: (code: string) => void,\n removeCoupon: () => void,\n clearCouponError: () => void,\n /** Code of the coupon just removed, set only once the removal round-trip\n * completes — kept in sync with when the discount actually leaves the line. */\n removedCouponCode: string | null,\n clearRemovedCouponCode: () => void,\n placingOrder: boolean,\n placeOrderError: string | null,\n /**\n * Accepts price (if needed) + terms, calls tCheckoutPlaceOrder with billing,\n * confirms the card via Stripe.js, then sets ?order_bi_id= to poll tPlacedOrder.\n * Fire-and-forget — errors go to placeOrderError state.\n */\n placeOrder: (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => void,\n /**\n * Same as placeOrder but returns a Promise — used by ExpressCheckout\n * so the wallet sheet can await the result and call ev.complete().\n */\n placeOrderAsync: (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => Promise<void>,\n clearPlaceOrderError: () => void,\n /** Decline details from the last card attempt on this checkout, if any. */\n paymentDecline: AlacartePaymentDecline | null,\n /** When ?order_bi_id= is present, the placed order (or null while polling). */\n placedOrder: PlacedOrder | null,\n awaitingPlacedOrder: boolean,\n placedOrderError: string | null,\n /** ISO timestamp the order was placed (tPlacedAt, falling back to\n * biCreatedAt); null while the order-dates query hasn't resolved yet. */\n placedOrderPlacedAt: string | null,\n}\n\n/**\n * Read the product selector from the URL: course_uid+course_run_key, or\n * program_uid, or neither. Both course params must be present together; if a\n * course param and a program param are both present, that's\n * CONFLICTING_SELECTION.\n *\n * NOTE: course_run_key values look like \"course-v1:HarvardX+CS50+X\" — nuqs\n * decodes query values the standards-compliant way (literal `+` -> space),\n * same as native URLSearchParams. This assumes whoever generates links into\n * this page percent-encodes `+` as %2B. Verify this in practice; see the plan\n * doc for the fallback if it's ever violated (drop nuqs for course_run_key\n * specifically).\n */\nexport function useProductSelector(): ProductSelector {\n const [{ courseUid, runKey, programUid }] = useQueryStates({\n courseUid: parseAsString,\n runKey: parseAsString,\n programUid: parseAsString,\n }, {\n urlKeys: {\n courseUid: 'course_uid',\n runKey: 'course_run_key',\n programUid: 'program_uid',\n },\n });\n\n return useMemo<ProductSelector>(() => {\n const hasCourse = !!courseUid || !!runKey;\n const hasProgram = !!programUid;\n if (hasCourse && hasProgram) return { kind: 'invalid' };\n if (courseUid && runKey) return { kind: 'course', courseUid, runKey };\n if (programUid) return { kind: 'program', programUid };\n return { kind: 'none' };\n }, [courseUid, runKey, programUid]);\n}\n\n/** Reads ?discount_code= — applied to the checkout right after it's created. */\nexport function useDiscountCode(): string | null {\n const [discountCode] = useQueryState('discount_code', parseAsString);\n return discountCode;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'Unknown error';\n}\n\n/**\n * Build a synthetic AlacarteLine from the owned-product pricing data so the\n * checkout overlay can show subtotal / deduction / total even when the backend\n * blocks tCheckoutSelect and returns no checkout object.\n */\nfunction buildLineFromOwnedProduct(product: OwnedProduct): AlacarteLine | null {\n if (!product.price) return null;\n const { full, deduction, amountDue, currency } = product.price;\n const toMoney = (amount: number): AlacarteMoney => ({ amount, currency });\n\n if (product.kind === 'program') {\n return {\n biiId: '',\n kind: 'program',\n programId: product.productId,\n programName: product.name,\n price: toMoney(full),\n deduction: deduction ? toMoney(deduction) : null,\n ownedCourses: product.ownedCourses.map((c) => ({\n courseId: c.courseId, name: c.name, via: c.via,\n })),\n discount: null,\n amountDue: toMoney(amountDue),\n billingAddressSet: false,\n };\n }\n\n return {\n biiId: '',\n kind: 'course',\n courseName: product.name,\n courseUid: product.productId,\n courseRunKey: '',\n seatType: 'verified',\n price: toMoney(full),\n discount: null,\n amountDue: toMoney(amountDue),\n billingAddressSet: false,\n };\n}\n\ninterface QueryLikeState<T> {\n isLoading: boolean,\n isError: boolean,\n error?: unknown,\n data?: T,\n}\n\ninterface MutationLikeState<T> {\n isIdle: boolean,\n isPending: boolean,\n isError: boolean,\n error?: unknown,\n data?: T,\n}\n\nexport interface DeriveAlacartePhaseInput {\n selector: ProductSelector,\n sessionReady: boolean,\n sessionIsError: boolean,\n sessionErrorMessage?: string,\n ownedQuery: QueryLikeState<OwnedProductResult>,\n selectMutation: MutationLikeState<AlacarteCheckoutResult>,\n checkoutQuery: QueryLikeState<AlacarteCheckoutResult>,\n productDetail: ProductDetail | null,\n /** Coupon (?discount_code=) applied right after the checkout is created —\n * when it succeeds, its checkout (with the coupon's discount reflected)\n * is shown in place of the pre-coupon one from selectMutation. */\n couponMutation?: MutationLikeState<AlacarteCheckoutResult>,\n /** True when a URL discount code still needs to be applied — the phase\n * stays 'loading' until the coupon mutation resolves so the user never sees\n * the pre-discount price flash. */\n urlCouponPending?: boolean,\n /** Latest successful manual update (coupon / acceptPrice / terms). Wins over\n * select + URL coupon when present. */\n checkoutOverride?: AlacarteCheckout | null,\n}\n\n/**\n * Pure decision function — no hooks, no React Query/nuqs types beyond plain\n * data — so every branch combination can be unit-tested directly.\n */\nexport function deriveAlacartePhase(input: DeriveAlacartePhaseInput): AlacartePhaseState {\n const {\n selector, sessionReady, sessionIsError, sessionErrorMessage,\n ownedQuery, selectMutation, checkoutQuery, productDetail, couponMutation,\n checkoutOverride = null, urlCouponPending: urlCouponPendingProp = false,\n } = input;\n\n const ownedProductName = ownedQuery.data?.product?.name ?? null;\n\n const empty: Omit<AlacartePhaseState, 'phase'> = {\n selector,\n checkout: null,\n line: null,\n productDetail: null,\n error: null,\n priceChanged: null,\n priceAccepted: false,\n isAlreadyOwned: false,\n ownedProductName: null,\n };\n\n const withCheckout = (\n checkout: AlacarteCheckout | null,\n priceChanged: AlacartePriceChanged | null = null,\n isAlreadyOwned = false,\n ): AlacartePhaseState => ({\n phase: isAlreadyOwned ? 'alreadyOwned' : 'ready',\n selector,\n checkout,\n line: checkout?.line ?? null,\n productDetail,\n error: null,\n priceChanged: priceChanged ?? null,\n priceAccepted: checkout?.priceAccepted === true,\n isAlreadyOwned,\n ownedProductName: isAlreadyOwned ? ownedProductName : null,\n });\n\n if (selector.kind === 'invalid') {\n return { phase: 'error', ...empty, error: 'CONFLICTING_SELECTION' };\n }\n if (sessionIsError) {\n return { phase: 'error', ...empty, error: sessionErrorMessage ?? 'Session error' };\n }\n\n const hasSelector = selector.kind === 'course' || selector.kind === 'program';\n\n if (hasSelector) {\n if (!sessionReady || ownedQuery.isLoading) {\n return { phase: 'loading', ...empty };\n }\n if (ownedQuery.isError) {\n return { phase: 'error', ...empty, error: errorMessage(ownedQuery.error) };\n }\n\n const isOwned = ownedQuery.data?.ok === true && ownedQuery.data.product?.status === 'full';\n\n if (selectMutation.isIdle || selectMutation.isPending) {\n return { phase: 'loading', ...empty };\n }\n if (selectMutation.isError) {\n return { phase: 'error', ...empty, error: errorMessage(selectMutation.error) };\n }\n if (selectMutation.data && !selectMutation.data.ok) {\n // The backend may block ALREADY_OWNED at select time. When the\n // blocked response still includes checkout data (line, pricing), use\n // it so the overlay page shows the real totals. Fall back to the\n // standalone tCheckout query, then to an empty state.\n if (selectMutation.data.blocked?.reason === 'ALREADY_OWNED') {\n const blockedCheckout = selectMutation.data.checkout\n ?? (checkoutQuery.data?.ok ? checkoutQuery.data.checkout : null);\n if (blockedCheckout) {\n return withCheckout(blockedCheckout, selectMutation.data.priceChanged ?? null, true);\n }\n // Build a synthetic line from the owned-product pricing so the\n // overlay can show subtotal / deduction / total.\n const ownedProduct = ownedQuery.data?.product;\n const syntheticLine = ownedProduct ? buildLineFromOwnedProduct(ownedProduct) : null;\n return {\n phase: 'alreadyOwned',\n noticeMessageId: selectMutation.data.blocked.kind === 'course' ? 'alreadyOwnedCourse' : 'alreadyOwnedProgram',\n ...empty,\n line: syntheticLine,\n productDetail,\n isAlreadyOwned: true,\n ownedProductName,\n };\n }\n if (selectMutation.data.blocked?.reason === 'NOT_PURCHASABLE') {\n return {\n phase: 'notPurchasable',\n ...empty,\n productDetail,\n error: selectMutation.data.blocked.kind === 'program'\n ? 'This program is not eligible for checkout.'\n : 'This course is not eligible for checkout.',\n };\n }\n const selectError = selectMutation.data.error;\n if (selectError === 'COURSE_NOT_FOUND' || selectError === 'PRODUCT_NOT_FOUND') {\n return {\n phase: 'error',\n ...empty,\n error: 'This course could not be found.',\n };\n }\n if (selectError === 'PROGRAM_NOT_FOUND') {\n return {\n phase: 'error',\n ...empty,\n error: 'This program could not be found.',\n };\n }\n const blockedDetail = selectMutation.data.blocked?.detail;\n return {\n phase: 'error',\n ...empty,\n error: blockedDetail ?? selectError ?? 'unknown',\n };\n }\n\n // When a URL discount code still needs to be applied, stay in 'loading'\n // so the user never sees the pre-discount price flash.\n if (urlCouponPendingProp && !checkoutOverride) {\n return { phase: 'loading', ...empty };\n }\n\n // Once the coupon-apply (?discount_code=) mutation succeeds, its checkout\n // (with the discount reflected) supersedes the pre-coupon one. Manual\n // updates (override) win over both.\n const finalCheckout = checkoutOverride\n ?? (couponMutation?.data?.ok\n ? couponMutation.data.checkout\n : selectMutation.data?.checkout ?? null);\n\n // When select succeeds but the owned-products query says the learner\n // already has this product, show the full checkout under an overlay.\n return withCheckout(\n finalCheckout,\n selectMutation.data?.priceChanged\n ?? (couponMutation?.data?.ok ? couponMutation.data.priceChanged : undefined)\n ?? null,\n isOwned,\n );\n }\n\n // No selector: fall back to the learner's existing open checkout, if any.\n if (!sessionReady || checkoutQuery.isLoading) {\n return { phase: 'loading', ...empty };\n }\n if (checkoutQuery.isError) {\n return { phase: 'error', ...empty, error: errorMessage(checkoutQuery.error) };\n }\n if (checkoutOverride || checkoutQuery.data?.checkout) {\n const checkout = checkoutOverride ?? checkoutQuery.data!.checkout;\n return withCheckout(checkout, checkoutQuery.data?.priceChanged ?? null);\n }\n\n return { phase: 'noActiveCheckout', noticeMessageId: 'noActiveCheckout', ...empty, isAlreadyOwned: false, ownedProductName: null };\n}\n\nexport function useAlacarteCheckout(\n options: { apiUrl?: string, edxSessionUrl?: string },\n): UseAlacarteCheckoutResult {\n const { apiUrl, edxSessionUrl } = options;\n const selector = useProductSelector();\n const discountCode = useDiscountCode();\n const [orderBiId, setOrderBiId] = useQueryState('order_bi_id', parseAsString);\n\n const client = useMemo(\n () => (apiUrl ? createAlacarteCheckoutClient({ apiUrl }) : null),\n [apiUrl],\n );\n\n // Reuses the same query key as useCheckout's session exchange — React\n // Query dedupes the network call regardless of how many hooks read it.\n const sessionQuery = useViaxSessionQuery(edxSessionUrl ?? null);\n const sessionReady = !!sessionQuery.data;\n\n useEffect(() => {\n if (sessionQuery.data && client) {\n client.setToken(sessionQuery.data.viaxToken);\n }\n }, [sessionQuery.data, client]);\n\n const hasSelector = selector.kind === 'course' || selector.kind === 'program';\n const productId = selector.kind === 'course'\n ? selector.courseUid\n : selector.kind === 'program' ? selector.programUid : null;\n\n const ownedQuery = useOwnedProductQuery(client, sessionReady && hasSelector, productId);\n const isOwned = ownedQuery.data?.ok === true && ownedQuery.data.product?.status === 'full';\n\n const selectMutation = useSelectProductMutation(client);\n const {\n isIdle: selectIsIdle, mutate: selectMutate, reset: selectReset,\n } = selectMutation;\n\n // Mutations aren't called during render — fire once the owned-products\n // query resolves (regardless of result) so we always get checkout/line data.\n // Pass viewedPrice from tOwnedProducts.amountDue (ALC-159) when available.\n useEffect(() => {\n if (!hasSelector || ownedQuery.isLoading || ownedQuery.isError) return;\n if (!selectIsIdle) return;\n const amountDue = ownedQuery.data?.product?.price?.amountDue;\n selectMutate({\n selector,\n viewedPrice: typeof amountDue === 'number' ? amountDue : undefined,\n });\n }, [\n hasSelector,\n ownedQuery.isLoading,\n ownedQuery.isError,\n ownedQuery.data?.product?.price?.amountDue,\n selector,\n selectIsIdle,\n selectMutate,\n ]);\n\n const productDetailEnabled = hasSelector && sessionReady && !ownedQuery.isLoading;\n const productDetailQuery = useProductDetailQuery(client, productDetailEnabled, selector);\n\n // Run the checkout query when there's no selector (standard path) OR when\n // the product is already owned — after the select mutation is blocked with\n // ALREADY_OWNED the server may still have an open checkout with pricing data.\n const selectBlocked = !selectMutation.isIdle && !selectMutation.isPending\n && selectMutation.data && !selectMutation.data.ok;\n const checkoutQuery = useAlacarteCheckoutQuery(\n client,\n sessionReady && (!hasSelector || (isOwned && !!selectBlocked)),\n );\n\n // Apply ?discount_code= to the freshly-created checkout — fired once the\n // select mutation succeeds with a checkout that doesn't already carry it.\n const urlCouponMutation = useUpdateCheckoutMutation(client);\n const {\n isIdle: couponIsIdle, mutate: couponMutate, reset: urlCouponReset,\n } = urlCouponMutation;\n const createdCheckout = selectMutation.data?.ok ? selectMutation.data.checkout : null;\n\n useEffect(() => {\n if (!createdCheckout || !discountCode) return;\n if (createdCheckout.couponCode === discountCode) return;\n if (couponIsIdle) {\n couponMutate({ biId: createdCheckout.biId, couponCode: discountCode });\n }\n }, [createdCheckout, discountCode, couponIsIdle, couponMutate]);\n\n const [checkoutOverride, setCheckoutOverride] = useState<AlacarteCheckout | null>(null);\n const [couponError, setCouponError] = useState<string | null>(null);\n const [removedCouponCode, setRemovedCouponCode] = useState<string | null>(null);\n const [placeOrderError, setPlaceOrderError] = useState<string | null>(null);\n const [placingOrder, setPlacingOrder] = useState(false);\n // biId of a checkout that's locked (CART_PAYMENT_PENDING) from a prior\n // tCheckoutPlaceOrder call whose Stripe confirmation was rejected\n // client-side. The next attempt must skip tCheckoutUpdate (it would fail\n // with CHECKOUT_NOT_OPEN) and go straight to tCheckoutPlaceOrder again.\n const [cardRetryBiId, setCardRetryBiId] = useState<string | null>(null);\n\n // Reset local overrides and in-flight select/coupon when the product changes\n // so viewedPrice / couponRecheck run again for the new selection.\n useEffect(() => {\n setCheckoutOverride(null);\n setCouponError(null);\n setRemovedCouponCode(null);\n setPlaceOrderError(null);\n setCardRetryBiId(null);\n selectReset();\n urlCouponReset();\n }, [selector, selectReset, urlCouponReset]);\n\n // Surface couponRecheck from product switch (section 2 of the API doc).\n useEffect(() => {\n const result = selectMutation.data;\n if (!result?.ok) return;\n const message = getCouponRecheckMessage(\n result.couponRecheck,\n result.checkout?.line?.discountSource,\n );\n if (message) setCouponError(message);\n }, [selectMutation.data]);\n\n // Surface ?discount_code= apply failures (domain ok:false or transport error).\n useEffect(() => {\n if (!discountCode) return;\n if (urlCouponMutation.isIdle || urlCouponMutation.isPending) return;\n if (urlCouponMutation.isError) {\n setCouponError(errorMessage(urlCouponMutation.error));\n return;\n }\n const result = urlCouponMutation.data;\n if (result && !result.ok) {\n setCouponError(getCouponErrorMessage(result.error, discountCode));\n }\n }, [\n discountCode,\n urlCouponMutation.isIdle,\n urlCouponMutation.isPending,\n urlCouponMutation.isError,\n urlCouponMutation.error,\n urlCouponMutation.data,\n ]);\n\n const manualUpdateMutation = useUpdateCheckoutMutation(client);\n\n const placedOrderQuery = usePlacedOrderQuery(\n client,\n orderBiId,\n sessionReady && !!orderBiId,\n );\n\n const orderDatesQuery = useOrderDatesQuery(\n client,\n orderBiId,\n sessionReady && !!orderBiId,\n );\n\n const derived = deriveAlacartePhase({\n selector,\n sessionReady,\n sessionIsError: sessionQuery.isError,\n sessionErrorMessage: sessionQuery.error?.message,\n ownedQuery: {\n isLoading: ownedQuery.isLoading,\n isError: ownedQuery.isError,\n error: ownedQuery.error,\n data: ownedQuery.data,\n },\n selectMutation: {\n isIdle: selectMutation.isIdle,\n isPending: selectMutation.isPending,\n isError: selectMutation.isError,\n error: selectMutation.error,\n data: selectMutation.data,\n },\n checkoutQuery: {\n isLoading: checkoutQuery.isLoading,\n isError: checkoutQuery.isError,\n error: checkoutQuery.error,\n data: checkoutQuery.data,\n },\n productDetail: productDetailQuery.data ?? null,\n couponMutation: {\n isIdle: urlCouponMutation.isIdle,\n isPending: urlCouponMutation.isPending,\n isError: urlCouponMutation.isError,\n error: urlCouponMutation.error,\n data: urlCouponMutation.data,\n },\n checkoutOverride,\n // The URL coupon is pending only when the checkout exists, doesn't already\n // carry the code, and the mutation hasn't completed yet. When the backend\n // returns the coupon pre-applied (couponCode === discountCode) or when\n // there's no discount_code param at all, this is false from the start.\n urlCouponPending: !!discountCode\n && !!createdCheckout\n && createdCheckout.couponCode !== discountCode\n && (urlCouponMutation.isIdle || urlCouponMutation.isPending),\n });\n\n const applyCoupon = useCallback((code: string) => {\n const biId = derived.checkout?.biId;\n if (!biId || !client) return;\n const trimmed = code.trim();\n if (!trimmed) return;\n\n setCouponError(null);\n manualUpdateMutation.mutate(\n { biId, couponCode: trimmed },\n {\n onSuccess: (result) => {\n if (result.ok && result.checkout) {\n setCheckoutOverride(result.checkout);\n setCouponError(null);\n setRemovedCouponCode(null);\n } else {\n setCouponError(getCouponErrorMessage(result.error, trimmed));\n }\n },\n onError: (err) => {\n setCouponError(errorMessage(err));\n },\n },\n );\n }, [derived.checkout?.biId, client, manualUpdateMutation]);\n\n const removeCoupon = useCallback(() => {\n const currentCheckout = derived.checkout;\n if (!currentCheckout?.biId || !client) return;\n const removedCode = currentCheckout.couponCode?.trim() || null;\n\n setCouponError(null);\n manualUpdateMutation.mutate(\n { biId: currentCheckout.biId, couponCode: '' },\n {\n onSuccess: (result) => {\n if (!result.ok) {\n setCouponError(getCouponErrorMessage(result.error));\n return;\n }\n // The backend may return a checkout whose line still carries the\n // old discount/amountDue. Always patch the line to clear the\n // coupon so the cart summary reflects the removal immediately.\n const base = result.checkout ?? currentCheckout;\n const line = base.line;\n const patchedLine = line\n ? {\n ...line,\n discount: null,\n amountDue: line.price && line.kind === 'program' && 'deduction' in line && line.deduction\n ? { amount: line.price.amount - line.deduction.amount, currency: line.price.currency }\n : line.price,\n } as typeof line\n : null;\n setCheckoutOverride({\n ...base,\n couponCode: null,\n line: patchedLine,\n });\n setCouponError(null);\n if (removedCode) setRemovedCouponCode(removedCode);\n },\n onError: (err) => {\n setCouponError(errorMessage(err));\n },\n },\n );\n }, [derived.checkout, client, manualUpdateMutation]);\n\n const placeOrderCore = useCallback(async (opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => {\n const checkout = derived.checkout;\n if (!checkout || !client) throw new Error('Checkout not ready');\n\n setPlacingOrder(true);\n setPlaceOrderError(null);\n\n try {\n const { checkout: updated } = await placeAlacarteOrder({\n updateCheckout: (args) => client.updateCheckout(args),\n placeCheckoutOrder: (biId, billing) => client.placeCheckoutOrder(biId, billing),\n checkout,\n billing: toAlacarteBillingAddress(opts.billing),\n confirmCardPayment: opts.confirmCardPayment,\n skipPrepare: cardRetryBiId === checkout.biId,\n });\n\n setCardRetryBiId(null);\n setCheckoutOverride(updated);\n await setOrderBiId(updated.biId);\n } catch (err: unknown) {\n if (err instanceof CardValidationError) {\n // tCheckoutPlaceOrder already succeeded and locked the checkout\n // (CART_PAYMENT_PENDING); Stripe rejected the card before it ever\n // reached the backend. Next attempt must retry tCheckoutPlaceOrder\n // directly, not tCheckoutUpdate.\n setCardRetryBiId(checkout.biId);\n } else {\n setCardRetryBiId(null);\n }\n if (err instanceof AlacartePlaceOrderError && err.checkout) {\n setCheckoutOverride(err.checkout);\n }\n setPlaceOrderError(errorMessage(err));\n throw err;\n } finally {\n setPlacingOrder(false);\n }\n }, [derived.checkout, client, setOrderBiId, cardRetryBiId]);\n\n /** Fire-and-forget wrapper for card payments. */\n const placeOrder = useCallback((opts: {\n billing: BillingInfo,\n confirmCardPayment: (clientSecret: string) => Promise<void>,\n }) => {\n if (placingOrder) return;\n placeOrderCore(opts).catch(() => { /* error already in state */ });\n }, [placeOrderCore, placingOrder]);\n\n const placedOrder = placedOrderQuery.data?.ok ? placedOrderQuery.data.order : null;\n\n const dates = orderDatesQuery.data?.ok ? orderDatesQuery.data.dates : null;\n const placedOrderPlacedAt = dates?.tPlacedAt ?? dates?.biCreatedAt ?? null;\n\n const placedOrderError = (() => {\n if (!orderBiId) return null;\n if (\n placedOrderQuery.data\n && !placedOrderQuery.data.ok\n && placedOrderQuery.data.error !== 'NOT_PLACED'\n && placedOrderQuery.data.error !== 'ORDER_READ_FAILED'\n ) {\n return placedOrderQuery.data.error ?? 'ORDER_READ_FAILED';\n }\n return null;\n })();\n\n return {\n ...derived,\n couponError,\n couponApplying: manualUpdateMutation.isPending,\n applyCoupon,\n removeCoupon,\n clearCouponError: () => setCouponError(null),\n removedCouponCode,\n clearRemovedCouponCode: () => setRemovedCouponCode(null),\n placingOrder,\n placeOrderError,\n placeOrder,\n placeOrderAsync: placeOrderCore,\n clearPlaceOrderError: () => setPlaceOrderError(null),\n paymentDecline: derived.checkout?.paymentDecline ?? null,\n placedOrder,\n awaitingPlacedOrder: !!orderBiId && !placedOrder && !placedOrderError && (\n placedOrderQuery.isLoading\n || placedOrderQuery.isFetching\n || placedOrderQuery.data?.error === 'NOT_PLACED'\n || placedOrderQuery.data?.error === 'ORDER_READ_FAILED'\n || (placedOrderQuery.data?.ok === true && !placedOrderQuery.data.order)\n || !placedOrderQuery.data\n ),\n placedOrderError,\n placedOrderPlacedAt,\n };\n}\n\nexport default useAlacarteCheckout;\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Shown when couponRecheck.outcome is unverified and the line no longer carries the coupon. */
|
|
2
2
|
export declare const COUPON_RECHECK_UNVERIFIED_MESSAGE = "We couldn't verify your promo code. Please try entering it again.";
|
|
3
|
-
export declare function getCouponErrorMessage(error?: string | null): string;
|
|
3
|
+
export declare function getCouponErrorMessage(error?: string | null, code?: string | null): string;
|
|
4
4
|
export declare function isCouponError(error?: string | null): boolean;
|
|
5
5
|
/**
|
|
6
6
|
* Learner-facing copy for couponRecheck on product switch (section 2).
|
|
@@ -10,4 +10,4 @@ export declare function isCouponError(error?: string | null): boolean;
|
|
|
10
10
|
export declare function getCouponRecheckMessage(recheck: {
|
|
11
11
|
outcome: string;
|
|
12
12
|
reason?: string | null;
|
|
13
|
-
} | null | undefined, discountSource?: string | null): string | null;
|
|
13
|
+
} | null | undefined, discountSource?: string | null, code?: string | null): string | null;
|
|
@@ -14,10 +14,18 @@ const COUPON_MESSAGES = {
|
|
|
14
14
|
};
|
|
15
15
|
/** Shown when couponRecheck.outcome is unverified and the line no longer carries the coupon. */
|
|
16
16
|
export const COUPON_RECHECK_UNVERIFIED_MESSAGE = "We couldn't verify your promo code. Please try entering it again.";
|
|
17
|
-
|
|
17
|
+
/** COUPON_INVALID needs the entered code interpolated, so it's built separately. */
|
|
18
|
+
function invalidCouponMessage(code) {
|
|
19
|
+
return code
|
|
20
|
+
? `Coupon code '${code}' does not exist. Please check the code and try again.`
|
|
21
|
+
: "This code doesn't exist";
|
|
22
|
+
}
|
|
23
|
+
export function getCouponErrorMessage(error, code) {
|
|
18
24
|
var _a;
|
|
19
25
|
if (!error)
|
|
20
26
|
return COUPON_MESSAGES.COUPON_REJECTED;
|
|
27
|
+
if (error === 'COUPON_INVALID')
|
|
28
|
+
return invalidCouponMessage(code);
|
|
21
29
|
return (_a = COUPON_MESSAGES[error]) !== null && _a !== void 0 ? _a : error;
|
|
22
30
|
}
|
|
23
31
|
export function isCouponError(error) {
|
|
@@ -28,11 +36,11 @@ export function isCouponError(error) {
|
|
|
28
36
|
* Returns null when nothing extra should be shown (`kept`, or `unverified` while
|
|
29
37
|
* the line still carries a coupon discount).
|
|
30
38
|
*/
|
|
31
|
-
export function getCouponRecheckMessage(recheck, discountSource) {
|
|
39
|
+
export function getCouponRecheckMessage(recheck, discountSource, code) {
|
|
32
40
|
if (!recheck)
|
|
33
41
|
return null;
|
|
34
42
|
if (recheck.outcome === 'rejected') {
|
|
35
|
-
return getCouponErrorMessage(recheck.reason);
|
|
43
|
+
return getCouponErrorMessage(recheck.reason, code);
|
|
36
44
|
}
|
|
37
45
|
if (recheck.outcome === 'unverified' && discountSource !== 'coupon') {
|
|
38
46
|
return COUPON_RECHECK_UNVERIFIED_MESSAGE;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"couponErrors.js","sourceRoot":"","sources":["../../src/utils/couponErrors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,eAAe,GAA2B;IAC9C,cAAc,EAAE,yBAAyB;IACzC,iBAAiB,EAAE,wBAAwB;IAC3C,cAAc,EAAE,uBAAuB;IACvC,kBAAkB,EAAE,mCAAmC;IACvD,2BAA2B,EAAE,oDAAoD;IACjF,yBAAyB,EAAE,4CAA4C;IACvE,yBAAyB,EAAE,+BAA+B;IAC1D,eAAe,EAAE,+BAA+B;CACjD,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,iCAAiC,GAAG,mEAAmE,CAAC;AAErH,MAAM,UAAU,qBAAqB,CAAC,KAAqB;;
|
|
1
|
+
{"version":3,"file":"couponErrors.js","sourceRoot":"","sources":["../../src/utils/couponErrors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,eAAe,GAA2B;IAC9C,cAAc,EAAE,yBAAyB;IACzC,iBAAiB,EAAE,wBAAwB;IAC3C,cAAc,EAAE,uBAAuB;IACvC,kBAAkB,EAAE,mCAAmC;IACvD,2BAA2B,EAAE,oDAAoD;IACjF,yBAAyB,EAAE,4CAA4C;IACvE,yBAAyB,EAAE,+BAA+B;IAC1D,eAAe,EAAE,+BAA+B;CACjD,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,iCAAiC,GAAG,mEAAmE,CAAC;AAErH,oFAAoF;AACpF,SAAS,oBAAoB,CAAC,IAAoB;IAChD,OAAO,IAAI;QACT,CAAC,CAAC,gBAAgB,IAAI,wDAAwD;QAC9E,CAAC,CAAC,yBAAyB,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAqB,EAAE,IAAoB;;IAC/E,IAAI,CAAC,KAAK;QAAE,OAAO,eAAe,CAAC,eAAe,CAAC;IACnD,IAAI,KAAK,KAAK,gBAAgB;QAAE,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,MAAA,eAAe,CAAC,KAAK,CAAC,mCAAI,KAAK,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAqB;IACjD,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,IAAI,eAAe,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAuE,EACvE,cAA8B,EAC9B,IAAoB;IAEpB,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,OAAO,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,KAAK,YAAY,IAAI,cAAc,KAAK,QAAQ,EAAE,CAAC;QACpE,OAAO,iCAAiC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/**\n * Learner-facing messages for tCheckoutUpdate coupon errors.\n * See alacarte-checkout-api.md section 7.\n */\nconst COUPON_MESSAGES: Record<string, string> = {\n COUPON_INVALID: \"This code doesn't exist\",\n COUPON_NOT_ACTIVE: \"This code isn't active\",\n COUPON_EXPIRED: 'This code has expired',\n COUPON_CAP_REACHED: 'This code has been fully redeemed',\n COUPON_PRODUCT_NOT_ELIGIBLE: \"This code can't be used for this course or program\",\n COUPON_PARTY_NOT_ELIGIBLE: \"This code isn't available for your account\",\n COUPON_PER_CUSTOMER_LIMIT: \"You've already used this code\",\n COUPON_REJECTED: \"This code couldn't be applied\",\n};\n\n/** Shown when couponRecheck.outcome is unverified and the line no longer carries the coupon. */\nexport const COUPON_RECHECK_UNVERIFIED_MESSAGE = \"We couldn't verify your promo code. Please try entering it again.\";\n\n/** COUPON_INVALID needs the entered code interpolated, so it's built separately. */\nfunction invalidCouponMessage(code?: string | null): string {\n return code\n ? `Coupon code '${code}' does not exist. Please check the code and try again.`\n : \"This code doesn't exist\";\n}\n\nexport function getCouponErrorMessage(error?: string | null, code?: string | null): string {\n if (!error) return COUPON_MESSAGES.COUPON_REJECTED;\n if (error === 'COUPON_INVALID') return invalidCouponMessage(code);\n return COUPON_MESSAGES[error] ?? error;\n}\n\nexport function isCouponError(error?: string | null): boolean {\n return !!error && error in COUPON_MESSAGES;\n}\n\n/**\n * Learner-facing copy for couponRecheck on product switch (section 2).\n * Returns null when nothing extra should be shown (`kept`, or `unverified` while\n * the line still carries a coupon discount).\n */\nexport function getCouponRecheckMessage(\n recheck: { outcome: string, reason?: string | null } | null | undefined,\n discountSource?: string | null,\n code?: string | null,\n): string | null {\n if (!recheck) return null;\n if (recheck.outcome === 'rejected') {\n return getCouponErrorMessage(recheck.reason, code);\n }\n if (recheck.outcome === 'unverified' && discountSource !== 'coupon') {\n return COUPON_RECHECK_UNVERIFIED_MESSAGE;\n }\n return null;\n}\n"]}
|
package/dist/utils/provision.js
CHANGED
|
@@ -21,8 +21,8 @@ import { EnvironmentTypes, getAppConfig, getSiteConfig } from '@openedx/frontend
|
|
|
21
21
|
import { appId } from '../constants';
|
|
22
22
|
/** Hardcoded edX JWT used only for local/dev checkout against stage Viax. */
|
|
23
23
|
const DEV_SESSION_BODY = {
|
|
24
|
-
payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.
|
|
25
|
-
signature: '
|
|
24
|
+
payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.eyJhdWQiOiJJbmtvY3VqTGlreXVjc0Vkd2lXYXRkZWJyRWFja21ldkxha0R1aWZLb29zaGtha1dvdyIsImV4cCI6MTc5MTgxNTc5MCwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwiaWF0IjoxNzkxODEyMTkwLCJpc3MiOiJodHRwczovL2NvdXJzZXMuc3RhZ2UuZWR4Lm9yZy9vYXV0aDIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJOU18yNjA5X1dLMzEiLCJzY29wZXMiOlsidXNlcl9pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJ2ZXJzaW9uIjoiMS4yLjAiLCJzdWIiOiI4MjE3ZWI5MTk0YTM1MGJiODVmYmUxMGUzNWFhYWNkZiIsImZpbHRlcnMiOlsidXNlcjptZSJdLCJpc19yZXN0cmljdGVkIjpmYWxzZSwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ1c2VyX2lkIjo1Mjg1MzcyLCJlbWFpbCI6Im5zb3Jva2FAMnUuY29tIiwibmFtZSI6Ik5pY29sYXMgU29yb2thIiwiZmFtaWx5X25hbWUiOiIiLCJnaXZlbl9uYW1lIjoiIiwiYWRtaW5pc3RyYXRvciI6ZmFsc2UsInN1cGVydXNlciI6ZmFsc2V9',
|
|
25
|
+
signature: 'B56DHXeCo_00XE1gyBX3BAMx-Fp2ObkfYWPLcN4-j_rpMVca_0GtgPGA32wtKliUVZkgl2uOBYeSb4UFc8YogUuj33IA5cExz5xEU9rsUSF4vrqwSKWeeUZarXPX9Nr45QDf4AoPyLzFgIWJuwqnZDR3IuOdpiZ8YkvBNBqq43XvoXK6ISuad6fG-fpRmLvxtebAlNytHfyJqmY_ySfzvL4vUdO0uW5au5gVRKwUu1wkfxA-Djt2MjEJkHXIS3CwukumJN7q867T9Ri_dMcmQRi78QmwazSo391CHgB7ovGQkbZ1BeClYRxbYJtHZwSiBIZqV8HVf1b7_wJAHVHmfA',
|
|
26
26
|
};
|
|
27
27
|
const EDX_JWT_PAYLOAD_COOKIE_NAMES = [
|
|
28
28
|
'stage-edx-jwt-cookie-header-payload',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provision.js","sourceRoot":"","sources":["../../src/utils/provision.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/provision.ts — exchange the edX session for a viax token.\n *\n * {LMS_BASE_URL}/api/edx-session\n * The LMS reads the edX JWT from browser cookies, exchanges it with viax,\n * and returns a per-user token for authenticated API calls.\n *\n * Dev uses POST with a hardcoded JWT payload (local LMS cookie exchange is\n * unavailable). Stage and prod use POST and rely on the browser session cookies.\n */\n\nimport { EnvironmentTypes, getAppConfig, getSiteConfig } from '@openedx/frontend-base';\nimport { appId } from '../constants';\n\nexport interface EdxSessionResult {\n viaxToken: string, // raw JWT — add 'Bearer ' prefix before use\n customerUid: string,\n partyUid?: string,\n edxUserId?: string,\n username?: string,\n email?: string,\n}\n\nexport interface GeolocationResult {\n status: 'resolved' | 'not_found' | 'error',\n ip_address: string,\n ip_address_type: string | null,\n country_code: string | null,\n country_name: string | null,\n region_code: string | null,\n region_name: string | null,\n city: string | null,\n postal_code: string | null,\n latitude: number | null,\n longitude: number | null,\n accuracy_radius_km: number | null,\n confidence: string | null,\n source: string | null,\n cache_status: string | null,\n looked_up_at: string | null,\n fallback_reason: string | null,\n}\n\n/** Hardcoded edX JWT used only for local/dev checkout against stage Viax. */\nconst DEV_SESSION_BODY = {\n payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.eyJhdWQiOiJJbmtvY3VqTGlreXVjc0Vkd2lXYXRkZWJyRWFja21ldkxha0R1aWZLb29zaGtha1dvdyIsImV4cCI6MTc5MTQwNzY5NiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwiaWF0IjoxNzkxNDA0MDk2LCJpc3MiOiJodHRwczovL2NvdXJzZXMuc3RhZ2UuZWR4Lm9yZy9vYXV0aDIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJBRF8yNjA5X0dQQ0EiLCJzY29wZXMiOlsidXNlcl9pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJ2ZXJzaW9uIjoiMS4yLjAiLCJzdWIiOiIxZDMyZDQwN2YxMTJkZjNiMmRhNWRjNjkxNjM1NWIzYiIsImZpbHRlcnMiOlsidXNlcjptZSJdLCJpc19yZXN0cmljdGVkIjpmYWxzZSwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ1c2VyX2lkIjo1Mjg1ODg5LCJlbWFpbCI6ImdpZ2FsYTgzODVAYnVsbGJhYnkuY29tIiwibmFtZSI6ImFrYXNoIGRldmdhbiIsImZhbWlseV9uYW1lIjoiIiwiZ2l2ZW5fbmFtZSI6IiIsImFkbWluaXN0cmF0b3IiOmZhbHNlLCJzdXBlcnVzZXIiOmZhbHNlfQ',\n signature: 'faXzzDPtisxK0QBWMSVagxfvlASwgbln-sjWg2FdklE3BLYVdzEZLIhObb3sehMADrQE2IH1qNFqhn1RbYZu1wNB3dlll-fPIk7LgYXaa92H3i1Ggyz2JTP_ZwZl62sEbnwK9zesWOGZVhuoVoJ4qO3HyuKj6sgem5SKGi2YG8ISlRskT-FBuYnEsVO7-BLr0qvxWLNU6pDQiINxM5a-G_yjcRQGYsZysHAw0-WxHj9zBB6YOIdTFdJGMvgyU11jryVjr1tHwEirVXphvfNlz5HCK_qIZlhvWZktl1anecAwdrj1WFgJAEbF3IUNlnMa8w6gloY__OQ2wDDiUeBrMA',\n};\n\nconst EDX_JWT_PAYLOAD_COOKIE_NAMES = [\n 'stage-edx-jwt-cookie-header-payload',\n 'edx-jwt-cookie-header-payload',\n];\n\nconst EDX_JWT_SIGNATURE_COOKIE_NAMES = [\n 'stage-edx-jwt-cookie-signature',\n 'edx-jwt-cookie-signature',\n];\n\nfunction getCookieValue(name: string): string | null {\n const cookie = document.cookie\n .split('; ')\n .find((cookiePart) => cookiePart.startsWith(`${name}=`));\n\n if (!cookie) return null;\n\n return decodeURIComponent(cookie.substring(name.length + 1));\n}\n\nfunction getFirstCookieValue(names: string[]): string | null {\n for (const name of names) {\n const value = getCookieValue(name);\n if (value) return value;\n }\n\n return null;\n}\n\nfunction getEdxJwtCookieBody(): { payload: string, signature: string } | null {\n const payload = getFirstCookieValue(EDX_JWT_PAYLOAD_COOKIE_NAMES);\n const signature = getFirstCookieValue(EDX_JWT_SIGNATURE_COOKIE_NAMES);\n\n return payload && signature ? { payload, signature } : null;\n}\n\nfunction parseSessionResponse(data: Record<string, unknown>): EdxSessionResult {\n const viaxToken = (\n data.viaxToken ?? data.token ?? data.access_token ?? data.accessToken\n ) as string | undefined;\n const customerUid = (data.customerUid ?? data.customer_uid) as string | undefined;\n\n if (!viaxToken) throw new Error('Session response missing viax token.');\n if (!customerUid) throw new Error('Session response missing customerUid.');\n\n return {\n viaxToken,\n customerUid,\n partyUid: data.partyUid as string | undefined,\n edxUserId: data.edxUserId as string | undefined,\n username: data.username as string | undefined,\n email: data.email as string | undefined,\n };\n}\n\n/**\n * Fetch the ISO 3166-1 alpha-2 country code from the user's edX account profile.\n * Returns null if the request fails or the field is absent.\n */\nexport async function fetchUserCountry(lmsBaseUrl: string, username: string): Promise<string | null> {\n try {\n const res = await fetch(`${lmsBaseUrl}/api/user/v1/accounts/${encodeURIComponent(username)}`, {\n credentials: 'include',\n });\n if (!res.ok) return null;\n const data = await res.json() as Record<string, unknown>;\n return typeof data.country === 'string' && data.country ? data.country : null;\n } catch {\n return null;\n }\n}\n\n/** Fetch the learner's current public IP for geolocation lookup. */\nexport async function fetchPublicIp(): Promise<string> {\n const res = await fetch('https://api.ipify.org?format=json', {\n headers: { Accept: 'application/json' },\n });\n\n if (!res.ok) {\n throw new Error(`Public IP lookup failed (${res.status}).`);\n }\n\n const data = await res.json() as { ip?: unknown };\n if (typeof data.ip !== 'string' || !data.ip) {\n throw new Error('Public IP lookup returned an invalid address.');\n }\n\n return data.ip;\n}\n\n/** Look up geolocation data for an explicit IP address. */\nexport async function fetchIpGeolocation(\n geolocationUrl: string,\n ipAddress: string,\n): Promise<GeolocationResult> {\n const edxJwtBody = getEdxJwtCookieBody();\n const requestBody = edxJwtBody\n ? { ip_address: ipAddress, ...edxJwtBody }\n : { ip_address: ipAddress };\n\n const res = await fetch(geolocationUrl, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!res.ok) {\n throw new Error(`Geolocation lookup failed (${res.status}).`);\n }\n\n return res.json() as Promise<GeolocationResult>;\n}\n\nfunction isDevelopment(): boolean {\n return getSiteConfig().environment === EnvironmentTypes.DEVELOPMENT;\n}\n\n/** Exchange the learner's edX session (cookies) for a viax token. */\nexport async function fetchEdxSession(sessionUrl: string): Promise<EdxSessionResult> {\n // When DEV_MOCK_SESSION is true, skip the network call entirely and return\n // the hardcoded response from site config. This avoids CORS errors when\n // testing over HTTPS locally (e.g. for Apple Pay / Google Pay).\n if (isDevelopment()) {\n try {\n const appConfig = getAppConfig(appId);\n if (appConfig.DEV_MOCK_SESSION) {\n const mock = appConfig.DEV_MOCK_SESSION_RESPONSE as Record<string, unknown>;\n if (mock) {\n return parseSessionResponse(mock);\n }\n }\n } catch {\n // getAppConfig may throw if called before init — fall through to the real fetch.\n }\n }\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n\n let res: Response;\n if (isDevelopment()) {\n res = await fetch(sessionUrl, {\n method: 'POST',\n credentials: 'include',\n headers: {\n ...headers,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(DEV_SESSION_BODY),\n });\n } else {\n res = await fetch(sessionUrl, {\n method: 'POST',\n credentials: 'include',\n headers,\n });\n }\n\n if (!res.ok) {\n throw new Error(\n `Failed to establish checkout session (${res.status}). Please log into edX and try again.`,\n );\n }\n\n const data = await res.json() as Record<string, unknown> & { error?: string };\n if (data.error) throw new Error(String(data.error));\n\n return parseSessionResponse(data);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provision.js","sourceRoot":"","sources":["../../src/utils/provision.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/provision.ts — exchange the edX session for a viax token.\n *\n * {LMS_BASE_URL}/api/edx-session\n * The LMS reads the edX JWT from browser cookies, exchanges it with viax,\n * and returns a per-user token for authenticated API calls.\n *\n * Dev uses POST with a hardcoded JWT payload (local LMS cookie exchange is\n * unavailable). Stage and prod use POST and rely on the browser session cookies.\n */\n\nimport { EnvironmentTypes, getAppConfig, getSiteConfig } from '@openedx/frontend-base';\nimport { appId } from '../constants';\n\nexport interface EdxSessionResult {\n viaxToken: string, // raw JWT — add 'Bearer ' prefix before use\n customerUid: string,\n partyUid?: string,\n edxUserId?: string,\n username?: string,\n email?: string,\n}\n\nexport interface GeolocationResult {\n status: 'resolved' | 'not_found' | 'error',\n ip_address: string,\n ip_address_type: string | null,\n country_code: string | null,\n country_name: string | null,\n region_code: string | null,\n region_name: string | null,\n city: string | null,\n postal_code: string | null,\n latitude: number | null,\n longitude: number | null,\n accuracy_radius_km: number | null,\n confidence: string | null,\n source: string | null,\n cache_status: string | null,\n looked_up_at: string | null,\n fallback_reason: string | null,\n}\n\n/** Hardcoded edX JWT used only for local/dev checkout against stage Viax. */\nconst DEV_SESSION_BODY = {\n payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.eyJhdWQiOiJJbmtvY3VqTGlreXVjc0Vkd2lXYXRkZWJyRWFja21ldkxha0R1aWZLb29zaGtha1dvdyIsImV4cCI6MTc5MTgxNTc5MCwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwiaWF0IjoxNzkxODEyMTkwLCJpc3MiOiJodHRwczovL2NvdXJzZXMuc3RhZ2UuZWR4Lm9yZy9vYXV0aDIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJOU18yNjA5X1dLMzEiLCJzY29wZXMiOlsidXNlcl9pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJ2ZXJzaW9uIjoiMS4yLjAiLCJzdWIiOiI4MjE3ZWI5MTk0YTM1MGJiODVmYmUxMGUzNWFhYWNkZiIsImZpbHRlcnMiOlsidXNlcjptZSJdLCJpc19yZXN0cmljdGVkIjpmYWxzZSwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ1c2VyX2lkIjo1Mjg1MzcyLCJlbWFpbCI6Im5zb3Jva2FAMnUuY29tIiwibmFtZSI6Ik5pY29sYXMgU29yb2thIiwiZmFtaWx5X25hbWUiOiIiLCJnaXZlbl9uYW1lIjoiIiwiYWRtaW5pc3RyYXRvciI6ZmFsc2UsInN1cGVydXNlciI6ZmFsc2V9',\n signature: 'B56DHXeCo_00XE1gyBX3BAMx-Fp2ObkfYWPLcN4-j_rpMVca_0GtgPGA32wtKliUVZkgl2uOBYeSb4UFc8YogUuj33IA5cExz5xEU9rsUSF4vrqwSKWeeUZarXPX9Nr45QDf4AoPyLzFgIWJuwqnZDR3IuOdpiZ8YkvBNBqq43XvoXK6ISuad6fG-fpRmLvxtebAlNytHfyJqmY_ySfzvL4vUdO0uW5au5gVRKwUu1wkfxA-Djt2MjEJkHXIS3CwukumJN7q867T9Ri_dMcmQRi78QmwazSo391CHgB7ovGQkbZ1BeClYRxbYJtHZwSiBIZqV8HVf1b7_wJAHVHmfA',\n};\n\nconst EDX_JWT_PAYLOAD_COOKIE_NAMES = [\n 'stage-edx-jwt-cookie-header-payload',\n 'edx-jwt-cookie-header-payload',\n];\n\nconst EDX_JWT_SIGNATURE_COOKIE_NAMES = [\n 'stage-edx-jwt-cookie-signature',\n 'edx-jwt-cookie-signature',\n];\n\nfunction getCookieValue(name: string): string | null {\n const cookie = document.cookie\n .split('; ')\n .find((cookiePart) => cookiePart.startsWith(`${name}=`));\n\n if (!cookie) return null;\n\n return decodeURIComponent(cookie.substring(name.length + 1));\n}\n\nfunction getFirstCookieValue(names: string[]): string | null {\n for (const name of names) {\n const value = getCookieValue(name);\n if (value) return value;\n }\n\n return null;\n}\n\nfunction getEdxJwtCookieBody(): { payload: string, signature: string } | null {\n const payload = getFirstCookieValue(EDX_JWT_PAYLOAD_COOKIE_NAMES);\n const signature = getFirstCookieValue(EDX_JWT_SIGNATURE_COOKIE_NAMES);\n\n return payload && signature ? { payload, signature } : null;\n}\n\nfunction parseSessionResponse(data: Record<string, unknown>): EdxSessionResult {\n const viaxToken = (\n data.viaxToken ?? data.token ?? data.access_token ?? data.accessToken\n ) as string | undefined;\n const customerUid = (data.customerUid ?? data.customer_uid) as string | undefined;\n\n if (!viaxToken) throw new Error('Session response missing viax token.');\n if (!customerUid) throw new Error('Session response missing customerUid.');\n\n return {\n viaxToken,\n customerUid,\n partyUid: data.partyUid as string | undefined,\n edxUserId: data.edxUserId as string | undefined,\n username: data.username as string | undefined,\n email: data.email as string | undefined,\n };\n}\n\n/**\n * Fetch the ISO 3166-1 alpha-2 country code from the user's edX account profile.\n * Returns null if the request fails or the field is absent.\n */\nexport async function fetchUserCountry(lmsBaseUrl: string, username: string): Promise<string | null> {\n try {\n const res = await fetch(`${lmsBaseUrl}/api/user/v1/accounts/${encodeURIComponent(username)}`, {\n credentials: 'include',\n });\n if (!res.ok) return null;\n const data = await res.json() as Record<string, unknown>;\n return typeof data.country === 'string' && data.country ? data.country : null;\n } catch {\n return null;\n }\n}\n\n/** Fetch the learner's current public IP for geolocation lookup. */\nexport async function fetchPublicIp(): Promise<string> {\n const res = await fetch('https://api.ipify.org?format=json', {\n headers: { Accept: 'application/json' },\n });\n\n if (!res.ok) {\n throw new Error(`Public IP lookup failed (${res.status}).`);\n }\n\n const data = await res.json() as { ip?: unknown };\n if (typeof data.ip !== 'string' || !data.ip) {\n throw new Error('Public IP lookup returned an invalid address.');\n }\n\n return data.ip;\n}\n\n/** Look up geolocation data for an explicit IP address. */\nexport async function fetchIpGeolocation(\n geolocationUrl: string,\n ipAddress: string,\n): Promise<GeolocationResult> {\n const edxJwtBody = getEdxJwtCookieBody();\n const requestBody = edxJwtBody\n ? { ip_address: ipAddress, ...edxJwtBody }\n : { ip_address: ipAddress };\n\n const res = await fetch(geolocationUrl, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!res.ok) {\n throw new Error(`Geolocation lookup failed (${res.status}).`);\n }\n\n return res.json() as Promise<GeolocationResult>;\n}\n\nfunction isDevelopment(): boolean {\n return getSiteConfig().environment === EnvironmentTypes.DEVELOPMENT;\n}\n\n/** Exchange the learner's edX session (cookies) for a viax token. */\nexport async function fetchEdxSession(sessionUrl: string): Promise<EdxSessionResult> {\n // When DEV_MOCK_SESSION is true, skip the network call entirely and return\n // the hardcoded response from site config. This avoids CORS errors when\n // testing over HTTPS locally (e.g. for Apple Pay / Google Pay).\n if (isDevelopment()) {\n try {\n const appConfig = getAppConfig(appId);\n if (appConfig.DEV_MOCK_SESSION) {\n const mock = appConfig.DEV_MOCK_SESSION_RESPONSE as Record<string, unknown>;\n if (mock) {\n return parseSessionResponse(mock);\n }\n }\n } catch {\n // getAppConfig may throw if called before init — fall through to the real fetch.\n }\n }\n\n const headers: Record<string, string> = { Accept: 'application/json' };\n\n let res: Response;\n if (isDevelopment()) {\n res = await fetch(sessionUrl, {\n method: 'POST',\n credentials: 'include',\n headers: {\n ...headers,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(DEV_SESSION_BODY),\n });\n } else {\n res = await fetch(sessionUrl, {\n method: 'POST',\n credentials: 'include',\n headers,\n });\n }\n\n if (!res.ok) {\n throw new Error(\n `Failed to establish checkout session (${res.status}). Please log into edX and try again.`,\n );\n }\n\n const data = await res.json() as Record<string, unknown> & { error?: string };\n if (data.error) throw new Error(String(data.error));\n\n return parseSessionResponse(data);\n}\n"]}
|