@edx/frontend-app-alacarte-checkout 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/components/CartSummary/CartSummary.d.ts +6 -3
  2. package/dist/components/CartSummary/CartSummary.js +3 -3
  3. package/dist/components/CartSummary/CartSummary.js.map +1 -1
  4. package/dist/components/Checkout/Checkout.js +22 -12
  5. package/dist/components/Checkout/Checkout.js.map +1 -1
  6. package/dist/components/Checkout/Messages.d.ts +25 -0
  7. package/dist/components/Checkout/Messages.js +25 -0
  8. package/dist/components/Checkout/Messages.js.map +1 -1
  9. package/dist/components/PaymentFields/PaymentFields.d.ts +7 -1
  10. package/dist/components/PaymentFields/PaymentFields.js +6 -1
  11. package/dist/components/PaymentFields/PaymentFields.js.map +1 -1
  12. package/dist/components/PaymentForm/Messages.d.ts +5 -0
  13. package/dist/components/PaymentForm/Messages.js +5 -0
  14. package/dist/components/PaymentForm/Messages.js.map +1 -1
  15. package/dist/components/PaymentForm/PaymentForm.d.ts +6 -2
  16. package/dist/components/PaymentForm/PaymentForm.js +42 -5
  17. package/dist/components/PaymentForm/PaymentForm.js.map +1 -1
  18. package/dist/components/PromoCode/PromoCode.js +4 -2
  19. package/dist/components/PromoCode/PromoCode.js.map +1 -1
  20. package/dist/data/hooks/useAlacarteCheckout.d.ts +7 -1
  21. package/dist/data/hooks/useAlacarteCheckout.js +112 -40
  22. package/dist/data/hooks/useAlacarteCheckout.js.map +1 -1
  23. package/dist/data/hooks/useCheckout.d.ts +3 -1
  24. package/dist/data/hooks/useCheckout.js +43 -1
  25. package/dist/data/hooks/useCheckout.js.map +1 -1
  26. package/dist/styles/components/checkout.scss +29 -1
  27. package/dist/styles/components/paymentFields.scss +36 -0
  28. package/dist/styles/components/paymentForm.scss +6 -0
  29. package/dist/styles/components/programEnrollmentCard.scss +13 -0
  30. package/dist/styles/components/promoCode.scss +76 -6
  31. package/dist/types/alacarte.d.ts +9 -0
  32. package/dist/types/alacarte.js.map +1 -1
  33. package/dist/types.d.ts +15 -0
  34. package/dist/types.js.map +1 -1
  35. package/dist/utils/provision.js +2 -2
  36. package/dist/utils/provision.js.map +1 -1
  37. package/package.json +1 -1
@@ -25,11 +25,14 @@ export interface CartSummaryProps {
25
25
  /** À la carte checkout line — when present, drives the subtotal/total and
26
26
  * the product name shown, in place of the generic edX Plus placeholder. */
27
27
  alacarteLine?: AlacarteLine | null;
28
- /** Program catalog detail (filterTwouProgram) — when the line is a program,
29
- * drives the "Courses included in this program" list. */
28
+ /** Program catalog detail (filterTwouProgram) — when present, drives the
29
+ * "Courses included in this program" list. */
30
30
  programDetail?: ProgramDetail | null;
31
+ /** Fallback program name — used when there is no alacarteLine to provide it
32
+ * (e.g. already-owned overlay). */
33
+ programName?: string | null;
31
34
  /** Coupon input — when set, wires PromoCode to tCheckoutUpdate. */
32
35
  promoCode?: PromoCodeProps | null;
33
36
  }
34
- declare const CartSummary: ({ productTitle, productBlurb, learnerCount: learnerCountProp, course, alacarteLine, programDetail, promoCode, }: CartSummaryProps) => import("react/jsx-runtime").JSX.Element;
37
+ declare const CartSummary: ({ productTitle, productBlurb, learnerCount: learnerCountProp, course, alacarteLine, programDetail, programName: programNameProp, promoCode, }: CartSummaryProps) => import("react/jsx-runtime").JSX.Element;
35
38
  export default CartSummary;
@@ -9,7 +9,7 @@ import PromoCode from '../PromoCode/PromoCode';
9
9
  import messages from './Messages';
10
10
  import learnersIcon from './world-icon.svg';
11
11
  import institutionsIcon from './student-icon.svg';
12
- const CartSummary = ({ productTitle, productBlurb, learnerCount: learnerCountProp, course = null, alacarteLine = null, programDetail = null, promoCode = null, }) => {
12
+ const CartSummary = ({ productTitle, productBlurb, learnerCount: learnerCountProp, course = null, alacarteLine = null, programDetail = null, programName: programNameProp = null, promoCode = null, }) => {
13
13
  var _a, _b, _c, _d;
14
14
  const { formatMessage } = useIntl();
15
15
  const title = productTitle !== null && productTitle !== void 0 ? productTitle : formatMessage(messages.productTitle);
@@ -33,7 +33,7 @@ const CartSummary = ({ productTitle, productBlurb, learnerCount: learnerCountPro
33
33
  : '';
34
34
  const lineName = alacarteLine
35
35
  ? (alacarteLine.kind === 'course' ? alacarteLine.courseName : alacarteLine.programName)
36
- : null;
36
+ : programNameProp;
37
37
  const ownedCourses = isProgramLine && alacarteLine.kind === 'program'
38
38
  ? ((_c = alacarteLine.ownedCourses) !== null && _c !== void 0 ? _c : [])
39
39
  : [];
@@ -47,7 +47,7 @@ const CartSummary = ({ productTitle, productBlurb, learnerCount: learnerCountPro
47
47
  : null;
48
48
  return (_jsxs("div", { className: "cart-summary ", children: [_jsxs(Card, { className: "cart-summary__card p-3", children: [_jsxs(Card.Section, { className: "d-flex justify-content-between align-items-center p-0 pb-3", children: [_jsx("span", { className: "font-weight-bold text-gray-900", children: formatMessage(messages.summaryHeading) }), !isProgramLine && (_jsxs(Badge, { variant: "light", className: "d-flex align-items-center px-2 py-1", children: [_jsx(Icon, { src: Group, className: "mr-1", style: { width: '1rem', height: '1rem' } }), subscriberCount == null ? (_jsx("span", { className: "cart-summary__count-skeleton", "aria-busy": "true", "aria-label": formatMessage(messages.loadingSubscribers), "data-testid": "subscriber-count-skeleton", children: _jsx(Skeleton, { width: 96, height: 12 }) })) : (formatMessage(messages.learnersSubscribed, {
49
49
  count: subscriberCount.toLocaleString(),
50
- }))] }))] }), _jsx(Card.Divider, {}), _jsxs(Card.Section, { className: "p-0 py-3", children: [course ? (_jsx(CourseEnrollmentCard, { course: course, variant: "summary" })) : isProgramLine && programDetail ? (_jsx(ProgramEnrollmentCard, { program: programDetail, programName: lineName !== null && lineName !== void 0 ? lineName : '' })) : lineName ? (_jsx("p", { className: "font-weight-bold mb-0 text-primary-500", children: lineName })) : (_jsxs("div", { className: "d-flex align-items-start", children: [_jsx(EdxUnlimitedLogo, { ariaLabel: "edX Plus" }), _jsxs("div", { children: [_jsx("p", { className: "font-weight-bold mb-0 text-primary-500", children: title }), _jsx("p", { className: "small mb-0 text-gray-900", children: blurb })] })] })), ownedCourseNames && (_jsx("p", { className: "cart-summary__already-yours small text-gray-700 mb-0 mt-2", "data-testid": "already-yours", children: formatMessage(messages.alreadyYours, { names: ownedCourseNames }) }))] }), _jsx(Card.Divider, {}), _jsxs(Card.Section, { className: "cart-summary__subtotal-row d-flex justify-content-between align-items-center p-0 pt-3", children: [_jsx("span", { className: "cart-summary__subtotal text-gray-900", children: formatMessage(messages.subtotal) }), _jsx("span", { className: "cart-summary__subtotal text-gray-900", children: subtotalText })] }), deduction && (_jsxs(Card.Section, { className: "d-flex justify-content-between align-items-center p-0", "data-testid": "deduction-row", children: [_jsx("span", { className: "text-gray-700", children: formatMessage(messages.deduction) }), _jsx("span", { className: "text-gray-700", children: formatMessage(messages.deductionAmount, {
50
+ }))] }))] }), _jsx(Card.Divider, {}), _jsxs(Card.Section, { className: "p-0 py-3", children: [course ? (_jsx(CourseEnrollmentCard, { course: course, variant: "summary" })) : programDetail ? (_jsx(ProgramEnrollmentCard, { program: programDetail, programName: lineName !== null && lineName !== void 0 ? lineName : '' })) : lineName ? (_jsx("p", { className: "font-weight-bold mb-0 text-primary-500", children: lineName })) : (_jsxs("div", { className: "d-flex align-items-start", children: [_jsx(EdxUnlimitedLogo, { ariaLabel: "edX Plus" }), _jsxs("div", { children: [_jsx("p", { className: "font-weight-bold mb-0 text-primary-500", children: title }), _jsx("p", { className: "small mb-0 text-gray-900", children: blurb })] })] })), ownedCourseNames && (_jsx("p", { className: "cart-summary__already-yours small text-gray-700 mb-0 mt-2", "data-testid": "already-yours", children: formatMessage(messages.alreadyYours, { names: ownedCourseNames }) }))] }), _jsx(Card.Divider, {}), _jsxs(Card.Section, { className: "cart-summary__subtotal-row d-flex justify-content-between align-items-center p-0 pt-3", children: [_jsx("span", { className: "cart-summary__subtotal text-gray-900", children: formatMessage(messages.subtotal) }), _jsx("span", { className: "cart-summary__subtotal text-gray-900", children: subtotalText })] }), deduction && (_jsxs(Card.Section, { className: "d-flex justify-content-between align-items-center p-0", "data-testid": "deduction-row", children: [_jsx("span", { className: "text-gray-700", children: formatMessage(messages.deduction) }), _jsx("span", { className: "text-gray-700", children: formatMessage(messages.deductionAmount, {
51
51
  amount: deduction.amount.toFixed(2),
52
52
  currency: deduction.currency,
53
53
  }) })] })), discount && (_jsxs(Card.Section, { className: "d-flex justify-content-between align-items-center p-0", "data-testid": "discount-row", children: [_jsx("span", { className: "text-success font-weight-bold", children: formatMessage(messages.discountApplied) }), _jsx("span", { className: "text-success font-weight-bold", children: formatMessage(messages.discountAmount, {
@@ -1 +1 @@
1
- {"version":3,"file":"CartSummary.js","sourceRoot":"","sources":["../../../src/components/CartSummary/CartSummary.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Badge, Card, Icon, Skeleton } from '@openedx/paragon';\nimport { Group } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport { EdxUnlimitedLogo } from '../BrandMarks/BrandMarks';\nimport CourseEnrollmentCard from '../CourseEnrollmentCard/CourseEnrollmentCard';\nimport ProgramEnrollmentCard from '../ProgramEnrollmentCard/ProgramEnrollmentCard';\nimport PromoCode from '../PromoCode/PromoCode';\nimport type { PromoCodeProps } from '../PromoCode/PromoCode';\nimport type { CourseDetail } from '../../types';\nimport type { AlacarteLine, ProgramDetail } from '../../types/alacarte';\nimport messages from './Messages';\nimport learnersIcon from './world-icon.svg';\nimport institutionsIcon from './student-icon.svg';\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport interface CartSummaryProps {\n productTitle?: string,\n productBlurb?: string,\n /** Promotional monthly price amount e.g. \"39\" */\n monthlyAmount?: string,\n /** Regular monthly price after the promo period e.g. \"59\" */\n monthlyRegularAmount?: string,\n /** Length of the promotional period in months */\n promoMonths?: number,\n /** Annual price amount e.g. \"299\" */\n annualAmount?: string,\n currency?: string,\n defaultCycle?: BillingCycle,\n monthlyRenewalLabel?: string,\n annualRenewalLabel?: string,\n /** Called when the learner switches monthly ↔ annual. */\n onCycleChange?: (cycle: BillingCycle) => void,\n learnerCount?: number,\n /** When set, shows the course enrollment preview card below the summary card. */\n course?: CourseDetail | null,\n /** À la carte checkout line — when present, drives the subtotal/total and\n * the product name shown, in place of the generic edX Plus placeholder. */\n alacarteLine?: AlacarteLine | null,\n /** Program catalog detail (filterTwouProgram) — when the line is a program,\n * drives the \"Courses included in this program\" list. */\n programDetail?: ProgramDetail | null,\n /** Coupon input — when set, wires PromoCode to tCheckoutUpdate. */\n promoCode?: PromoCodeProps | null,\n}\n\nconst CartSummary = ({\n productTitle,\n productBlurb,\n learnerCount: learnerCountProp,\n course = null,\n alacarteLine = null,\n programDetail = null,\n promoCode = null,\n}: CartSummaryProps) => {\n const { formatMessage } = useIntl();\n const title = productTitle ?? formatMessage(messages.productTitle);\n const blurb = productBlurb ?? formatMessage(messages.productBlurb);\n\n // Prefer the course's own enrollment count. Programs have no equivalent field\n // — the badge is hidden for those rather than inventing a figure.\n const isProgramLine = alacarteLine?.kind === 'program';\n const subscriberCount = course?.tEnrollmentCount ?? learnerCountProp ?? null;\n\n // No fallback amount — an unresolved à la carte line means we don't know\n // the price yet, so the row is left blank rather than showing a made-up\n // number that could be mistaken for the real one.\n const subtotalText = alacarteLine?.price\n ? formatMessage(messages.subtotalAmount, {\n amount: alacarteLine.price.amount.toFixed(2), currency: alacarteLine.price.currency,\n })\n : '';\n const totalText = alacarteLine?.amountDue\n ? formatMessage(messages.todaysTotalValue, {\n amount: alacarteLine.amountDue.amount.toFixed(2), currency: alacarteLine.amountDue.currency,\n })\n : '';\n\n const lineName = alacarteLine\n ? (alacarteLine.kind === 'course' ? alacarteLine.courseName : alacarteLine.programName)\n : null;\n\n const ownedCourses = isProgramLine && alacarteLine.kind === 'program'\n ? (alacarteLine.ownedCourses ?? [])\n : [];\n const ownedCourseNames = ownedCourses\n .map((c) => c.name)\n .filter(Boolean)\n .join(', ');\n const discount = alacarteLine?.discount ?? null;\n\n const deduction = isProgramLine && alacarteLine.kind === 'program'\n ? alacarteLine.deduction\n : null;\n\n return (\n <div className=\"cart-summary \">\n <Card className=\"cart-summary__card p-3\">\n <Card.Section className=\"d-flex justify-content-between align-items-center p-0 pb-3\">\n <span className=\"font-weight-bold text-gray-900\">\n {formatMessage(messages.summaryHeading)}\n </span>\n {!isProgramLine && (\n <Badge\n variant=\"light\"\n className=\"d-flex align-items-center px-2 py-1\"\n >\n <Icon\n src={Group}\n className=\"mr-1\"\n style={{ width: '1rem', height: '1rem' }}\n />\n {subscriberCount == null ? (\n <span\n className=\"cart-summary__count-skeleton\"\n aria-busy=\"true\"\n aria-label={formatMessage(messages.loadingSubscribers)}\n data-testid=\"subscriber-count-skeleton\"\n >\n <Skeleton width={96} height={12} />\n </span>\n ) : (\n formatMessage(messages.learnersSubscribed, {\n count: subscriberCount.toLocaleString(),\n })\n )}\n </Badge>\n )}\n </Card.Section>\n\n <Card.Divider />\n\n <Card.Section className=\"p-0 py-3\">\n {course ? (\n <CourseEnrollmentCard course={course} variant=\"summary\" />\n ) : isProgramLine && programDetail ? (\n <ProgramEnrollmentCard program={programDetail} programName={lineName ?? ''} />\n ) : lineName ? (\n <p className=\"font-weight-bold mb-0 text-primary-500\">{lineName}</p>\n ) : (\n <div className=\"d-flex align-items-start\">\n <EdxUnlimitedLogo ariaLabel=\"edX Plus\" />\n <div>\n <p className=\"font-weight-bold mb-0 text-primary-500\">{title}</p>\n <p className=\"small mb-0 text-gray-900\">{blurb}</p>\n </div>\n </div>\n )}\n {ownedCourseNames && (\n <p\n className=\"cart-summary__already-yours small text-gray-700 mb-0 mt-2\"\n data-testid=\"already-yours\"\n >\n {formatMessage(messages.alreadyYours, { names: ownedCourseNames })}\n </p>\n )}\n </Card.Section>\n\n <Card.Divider />\n\n <Card.Section className=\"cart-summary__subtotal-row d-flex justify-content-between align-items-center p-0 pt-3\">\n <span className=\"cart-summary__subtotal text-gray-900\">\n {formatMessage(messages.subtotal)}\n </span>\n <span className=\"cart-summary__subtotal text-gray-900\">\n {subtotalText}\n </span>\n </Card.Section>\n\n {deduction && (\n <Card.Section\n className=\"d-flex justify-content-between align-items-center p-0\"\n data-testid=\"deduction-row\"\n >\n <span className=\"text-gray-700\">\n {formatMessage(messages.deduction)}\n </span>\n <span className=\"text-gray-700\">\n {formatMessage(messages.deductionAmount, {\n amount: deduction.amount.toFixed(2),\n currency: deduction.currency,\n })}\n </span>\n </Card.Section>\n )}\n\n {discount && (\n <Card.Section\n className=\"d-flex justify-content-between align-items-center p-0\"\n data-testid=\"discount-row\"\n >\n <span className=\"text-success font-weight-bold\">\n {formatMessage(messages.discountApplied)}\n </span>\n <span className=\"text-success font-weight-bold\">\n {formatMessage(messages.discountAmount, {\n amount: discount.amount.toFixed(2),\n currency: discount.currency,\n })}\n </span>\n </Card.Section>\n )}\n\n <Card.Section className=\"d-flex justify-content-between align-items-center p-0\">\n <span className=\"cart-summary__total-label text-gray-900\">\n {formatMessage(messages.todaysTotal)}\n </span>\n <span className=\"cart-summary__total-value mb-0 text-gray-900\">\n {totalText}\n </span>\n </Card.Section>\n </Card>\n\n {promoCode ? <PromoCode {...promoCode} /> : null}\n\n {/* Stats row */}\n <div className=\"cart-summary__stats d-none d-lg-flex\">\n <div className=\"cart-summary__stat d-flex align-items-center mr-4\">\n <img src={learnersIcon} alt=\"\" width={50} height={50} className=\"mr-2\" />\n <div>\n <p className=\"cart-summary__stat-count font-weight-bold text-gray-500 mb-0\">\n {formatMessage(messages.learnersCount)}\n </p>\n <p className=\"cart-summary__stat-label text-gray-500 mb-0\">\n {formatMessage(messages.learnersLabel)}\n </p>\n </div>\n </div>\n <div className=\"cart-summary__stat d-flex align-items-center\">\n <img src={institutionsIcon} alt=\"\" width={50} height={50} className=\"mr-2\" />\n <div>\n <p className=\"cart-summary__stat-count font-weight-bold text-gray-500 mb-0\">\n {formatMessage(messages.institutionsCount)}\n </p>\n <p className=\"cart-summary__stat-label text-gray-500 mb-0\">\n {formatMessage(messages.institutionsLabel)}\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CartSummary;\n"]}
1
+ {"version":3,"file":"CartSummary.js","sourceRoot":"","sources":["../../../src/components/CartSummary/CartSummary.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Badge, Card, Icon, Skeleton } from '@openedx/paragon';\nimport { Group } from '@openedx/paragon/icons';\nimport { useIntl } from '@openedx/frontend-base';\nimport { EdxUnlimitedLogo } from '../BrandMarks/BrandMarks';\nimport CourseEnrollmentCard from '../CourseEnrollmentCard/CourseEnrollmentCard';\nimport ProgramEnrollmentCard from '../ProgramEnrollmentCard/ProgramEnrollmentCard';\nimport PromoCode from '../PromoCode/PromoCode';\nimport type { PromoCodeProps } from '../PromoCode/PromoCode';\nimport type { CourseDetail } from '../../types';\nimport type { AlacarteLine, ProgramDetail } from '../../types/alacarte';\nimport messages from './Messages';\nimport learnersIcon from './world-icon.svg';\nimport institutionsIcon from './student-icon.svg';\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport interface CartSummaryProps {\n productTitle?: string,\n productBlurb?: string,\n /** Promotional monthly price amount e.g. \"39\" */\n monthlyAmount?: string,\n /** Regular monthly price after the promo period e.g. \"59\" */\n monthlyRegularAmount?: string,\n /** Length of the promotional period in months */\n promoMonths?: number,\n /** Annual price amount e.g. \"299\" */\n annualAmount?: string,\n currency?: string,\n defaultCycle?: BillingCycle,\n monthlyRenewalLabel?: string,\n annualRenewalLabel?: string,\n /** Called when the learner switches monthly ↔ annual. */\n onCycleChange?: (cycle: BillingCycle) => void,\n learnerCount?: number,\n /** When set, shows the course enrollment preview card below the summary card. */\n course?: CourseDetail | null,\n /** À la carte checkout line — when present, drives the subtotal/total and\n * the product name shown, in place of the generic edX Plus placeholder. */\n alacarteLine?: AlacarteLine | null,\n /** Program catalog detail (filterTwouProgram) — when present, drives the\n * \"Courses included in this program\" list. */\n programDetail?: ProgramDetail | null,\n /** Fallback program name — used when there is no alacarteLine to provide it\n * (e.g. already-owned overlay). */\n programName?: string | null,\n /** Coupon input — when set, wires PromoCode to tCheckoutUpdate. */\n promoCode?: PromoCodeProps | null,\n}\n\nconst CartSummary = ({\n productTitle,\n productBlurb,\n learnerCount: learnerCountProp,\n course = null,\n alacarteLine = null,\n programDetail = null,\n programName: programNameProp = null,\n promoCode = null,\n}: CartSummaryProps) => {\n const { formatMessage } = useIntl();\n const title = productTitle ?? formatMessage(messages.productTitle);\n const blurb = productBlurb ?? formatMessage(messages.productBlurb);\n\n // Prefer the course's own enrollment count. Programs have no equivalent field\n // — the badge is hidden for those rather than inventing a figure.\n const isProgramLine = alacarteLine?.kind === 'program';\n const subscriberCount = course?.tEnrollmentCount ?? learnerCountProp ?? null;\n\n // No fallback amount — an unresolved à la carte line means we don't know\n // the price yet, so the row is left blank rather than showing a made-up\n // number that could be mistaken for the real one.\n const subtotalText = alacarteLine?.price\n ? formatMessage(messages.subtotalAmount, {\n amount: alacarteLine.price.amount.toFixed(2), currency: alacarteLine.price.currency,\n })\n : '';\n const totalText = alacarteLine?.amountDue\n ? formatMessage(messages.todaysTotalValue, {\n amount: alacarteLine.amountDue.amount.toFixed(2), currency: alacarteLine.amountDue.currency,\n })\n : '';\n\n const lineName = alacarteLine\n ? (alacarteLine.kind === 'course' ? alacarteLine.courseName : alacarteLine.programName)\n : programNameProp;\n\n const ownedCourses = isProgramLine && alacarteLine.kind === 'program'\n ? (alacarteLine.ownedCourses ?? [])\n : [];\n const ownedCourseNames = ownedCourses\n .map((c) => c.name)\n .filter(Boolean)\n .join(', ');\n const discount = alacarteLine?.discount ?? null;\n\n const deduction = isProgramLine && alacarteLine.kind === 'program'\n ? alacarteLine.deduction\n : null;\n\n return (\n <div className=\"cart-summary \">\n <Card className=\"cart-summary__card p-3\">\n <Card.Section className=\"d-flex justify-content-between align-items-center p-0 pb-3\">\n <span className=\"font-weight-bold text-gray-900\">\n {formatMessage(messages.summaryHeading)}\n </span>\n {!isProgramLine && (\n <Badge\n variant=\"light\"\n className=\"d-flex align-items-center px-2 py-1\"\n >\n <Icon\n src={Group}\n className=\"mr-1\"\n style={{ width: '1rem', height: '1rem' }}\n />\n {subscriberCount == null ? (\n <span\n className=\"cart-summary__count-skeleton\"\n aria-busy=\"true\"\n aria-label={formatMessage(messages.loadingSubscribers)}\n data-testid=\"subscriber-count-skeleton\"\n >\n <Skeleton width={96} height={12} />\n </span>\n ) : (\n formatMessage(messages.learnersSubscribed, {\n count: subscriberCount.toLocaleString(),\n })\n )}\n </Badge>\n )}\n </Card.Section>\n\n <Card.Divider />\n\n <Card.Section className=\"p-0 py-3\">\n {course ? (\n <CourseEnrollmentCard course={course} variant=\"summary\" />\n ) : programDetail ? (\n <ProgramEnrollmentCard program={programDetail} programName={lineName ?? ''} />\n ) : lineName ? (\n <p className=\"font-weight-bold mb-0 text-primary-500\">{lineName}</p>\n ) : (\n <div className=\"d-flex align-items-start\">\n <EdxUnlimitedLogo ariaLabel=\"edX Plus\" />\n <div>\n <p className=\"font-weight-bold mb-0 text-primary-500\">{title}</p>\n <p className=\"small mb-0 text-gray-900\">{blurb}</p>\n </div>\n </div>\n )}\n {ownedCourseNames && (\n <p\n className=\"cart-summary__already-yours small text-gray-700 mb-0 mt-2\"\n data-testid=\"already-yours\"\n >\n {formatMessage(messages.alreadyYours, { names: ownedCourseNames })}\n </p>\n )}\n </Card.Section>\n\n <Card.Divider />\n\n <Card.Section className=\"cart-summary__subtotal-row d-flex justify-content-between align-items-center p-0 pt-3\">\n <span className=\"cart-summary__subtotal text-gray-900\">\n {formatMessage(messages.subtotal)}\n </span>\n <span className=\"cart-summary__subtotal text-gray-900\">\n {subtotalText}\n </span>\n </Card.Section>\n\n {deduction && (\n <Card.Section\n className=\"d-flex justify-content-between align-items-center p-0\"\n data-testid=\"deduction-row\"\n >\n <span className=\"text-gray-700\">\n {formatMessage(messages.deduction)}\n </span>\n <span className=\"text-gray-700\">\n {formatMessage(messages.deductionAmount, {\n amount: deduction.amount.toFixed(2),\n currency: deduction.currency,\n })}\n </span>\n </Card.Section>\n )}\n\n {discount && (\n <Card.Section\n className=\"d-flex justify-content-between align-items-center p-0\"\n data-testid=\"discount-row\"\n >\n <span className=\"text-success font-weight-bold\">\n {formatMessage(messages.discountApplied)}\n </span>\n <span className=\"text-success font-weight-bold\">\n {formatMessage(messages.discountAmount, {\n amount: discount.amount.toFixed(2),\n currency: discount.currency,\n })}\n </span>\n </Card.Section>\n )}\n\n <Card.Section className=\"d-flex justify-content-between align-items-center p-0\">\n <span className=\"cart-summary__total-label text-gray-900\">\n {formatMessage(messages.todaysTotal)}\n </span>\n <span className=\"cart-summary__total-value mb-0 text-gray-900\">\n {totalText}\n </span>\n </Card.Section>\n </Card>\n\n {promoCode ? <PromoCode {...promoCode} /> : null}\n\n {/* Stats row */}\n <div className=\"cart-summary__stats d-none d-lg-flex\">\n <div className=\"cart-summary__stat d-flex align-items-center mr-4\">\n <img src={learnersIcon} alt=\"\" width={50} height={50} className=\"mr-2\" />\n <div>\n <p className=\"cart-summary__stat-count font-weight-bold text-gray-500 mb-0\">\n {formatMessage(messages.learnersCount)}\n </p>\n <p className=\"cart-summary__stat-label text-gray-500 mb-0\">\n {formatMessage(messages.learnersLabel)}\n </p>\n </div>\n </div>\n <div className=\"cart-summary__stat d-flex align-items-center\">\n <img src={institutionsIcon} alt=\"\" width={50} height={50} className=\"mr-2\" />\n <div>\n <p className=\"cart-summary__stat-count font-weight-bold text-gray-500 mb-0\">\n {formatMessage(messages.institutionsCount)}\n </p>\n <p className=\"cart-summary__stat-label text-gray-500 mb-0\">\n {formatMessage(messages.institutionsLabel)}\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CartSummary;\n"]}
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  };
21
21
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
22
22
  import { useCallback, useEffect, useState } from 'react';
23
- import { Alert, Col, Row } from '@openedx/paragon';
23
+ import { Alert, Button, Col, Row } from '@openedx/paragon';
24
24
  import { CheckCircle, Error as ErrorIcon } from '@openedx/paragon/icons';
25
25
  import { useIntl } from '@openedx/frontend-base';
26
26
  import useCheckout from '../../data/hooks/useCheckout';
@@ -44,17 +44,18 @@ import messages from './Messages';
44
44
  // Flip back to true to restore the redirect.
45
45
  const REDIRECT_ON_NO_ACTIVE_CHECKOUT = false;
46
46
  const Checkout = (_a) => {
47
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
47
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
48
48
  var { homeUrl = '/', orderHistoryUrl } = _a, props = __rest(_a, ["homeUrl", "orderHistoryUrl"]);
49
49
  const { formatMessage } = useIntl();
50
50
  const alacarte = useAlacarteCheckout({ apiUrl: props.apiUrl, edxSessionUrl: props.edxSessionUrl });
51
51
  const c = useCheckout(props);
52
52
  const [promoCodeValue, setPromoCodeValue] = useState('');
53
53
  const [dismissedCouponAlert, setDismissedCouponAlert] = useState(null);
54
+ const [showValidationBanner, setShowValidationBanner] = useState(false);
54
55
  // Last code we successfully priced — drives the "Save {percent}% with code
55
56
  // {code}" hint on the empty field while a coupon is not yet applied.
56
57
  const [advertisedOffer, setAdvertisedOffer] = useState(null);
57
- const isAlacarteReady = alacarte.phase === 'ready' && !!alacarte.checkout;
58
+ const isAlacarteReady = (alacarte.phase === 'ready' || alacarte.phase === 'alreadyOwned') && !!alacarte.checkout;
58
59
  const appliedCouponCode = ((_c = (_b = alacarte.checkout) === null || _b === void 0 ? void 0 : _b.couponCode) === null || _c === void 0 ? void 0 : _c.trim())
59
60
  ? alacarte.checkout.couponCode.trim()
60
61
  : null;
@@ -120,11 +121,14 @@ const Checkout = (_a) => {
120
121
  const selectedCycle = c.selectedCycle;
121
122
  // Prefer the à la carte course's own detail (skills/badge/image, richer than
122
123
  // the subscription flow's ?course_run_key= lookup) when we selected a course.
123
- const alacarteCourseDetail = ((_f = alacarte.line) === null || _f === void 0 ? void 0 : _f.kind) === 'course' && alacarte.productDetail && 'maId' in alacarte.productDetail
124
+ // When already-owned the line may be null, so fall back to the selector kind.
125
+ const isCourseProduct = ((_f = alacarte.line) === null || _f === void 0 ? void 0 : _f.kind) === 'course' || ((_g = alacarte.selector) === null || _g === void 0 ? void 0 : _g.kind) === 'course';
126
+ const isProgramProduct = ((_h = alacarte.line) === null || _h === void 0 ? void 0 : _h.kind) === 'program' || ((_j = alacarte.selector) === null || _j === void 0 ? void 0 : _j.kind) === 'program';
127
+ const alacarteCourseDetail = isCourseProduct && alacarte.productDetail && 'maId' in alacarte.productDetail
124
128
  ? alacarte.productDetail
125
129
  : null;
126
130
  const courseForSummary = alacarteCourseDetail !== null && alacarteCourseDetail !== void 0 ? alacarteCourseDetail : c.course;
127
- const alacarteProgramDetail = ((_g = alacarte.line) === null || _g === void 0 ? void 0 : _g.kind) === 'program' && alacarte.productDetail && 'tCourses' in alacarte.productDetail
131
+ const alacarteProgramDetail = isProgramProduct && alacarte.productDetail && 'tCourses' in alacarte.productDetail
128
132
  ? alacarte.productDetail
129
133
  : null;
130
134
  const handleStartCourse = () => {
@@ -159,9 +163,9 @@ const Checkout = (_a) => {
159
163
  // tPlacedOrder is still polling, keep the checkout form so Pay now can show
160
164
  // "Processing..." instead of a full-page loader.
161
165
  if (alacarte.placedOrder || alacarte.placedOrderError) {
162
- const confirmationTitle = ((_h = alacarte.line) === null || _h === void 0 ? void 0 : _h.kind) === 'program'
166
+ const confirmationTitle = ((_k = alacarte.line) === null || _k === void 0 ? void 0 : _k.kind) === 'program'
163
167
  ? alacarte.line.programName
164
- : ((_j = alacarte.line) === null || _j === void 0 ? void 0 : _j.kind) === 'course'
168
+ : ((_l = alacarte.line) === null || _l === void 0 ? void 0 : _l.kind) === 'course'
165
169
  ? alacarte.line.courseName
166
170
  : null;
167
171
  return (_jsxs(_Fragment, { children: [alacarteDebug, _jsx(Row, { className: "checkout__container bg-light-200", children: _jsx(Col, { xs: 12, children: _jsx(AlacarteConfirmation, { order: alacarte.placedOrder, awaiting: false, error: alacarte.placedOrderError, onContinue: handleStartCourse, productDetail: alacarte.productDetail, productTitle: confirmationTitle, orderHistoryUrl: orderHistoryUrl !== null && orderHistoryUrl !== void 0 ? orderHistoryUrl : null }) }) })] }));
@@ -174,17 +178,23 @@ const Checkout = (_a) => {
174
178
  // notice while that happens.
175
179
  return (_jsxs(_Fragment, { children: [alacarteDebug, _jsx(ProcessingScreen, {})] }));
176
180
  }
177
- if (alacarte.phase === 'alreadyOwned' || alacarte.phase === 'noActiveCheckout') {
181
+ if (alacarte.phase === 'noActiveCheckout') {
178
182
  return (_jsxs(_Fragment, { children: [alacarteDebug, _jsx(AlacarteNotice, { messageId: alacarte.noticeMessageId })] }));
179
183
  }
180
- return (_jsxs(_Fragment, { children: [alacarteDebug, _jsxs(Row, { className: "checkout__container bg-light-200", children: [_jsx(CountryUnavailableModal, { isOpen: isBillingCountryBlocked, homeUrl: homeUrl }), _jsx(Col, { xs: 12, className: "d-lg-none", children: _jsx("h1", { className: "font-weight-bold text-primary-900", children: "Checkout" }) }), _jsx(Col, { xs: 12, children: _jsxs(Row, { className: "flex-column-reverse gap-5 flex-lg-row", children: [_jsx(Col, { xs: 12, lg: 7, xxl: 9, className: "payment__options", children: _jsxs("div", { children: [_jsx("h1", { className: "font-weight-bold text-primary-900 d-none d-lg-block mb-4", children: "Checkout" }), c.error && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: c.clearError, children: c.error })), alacarte.placeOrderError && (_jsx(Alert, { variant: "warning", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearPlaceOrderError, className: "mb-3", children: alacarte.placeOrderError })), !alacarte.priceAccepted && isAlacarteReady && ((_k = alacarte.line) === null || _k === void 0 ? void 0 : _k.amountDue) && (_jsx(Alert, { variant: "info", className: "mb-3", "data-testid": "price-accept-notice", children: formatMessage(messages.priceChangedNotice, {
184
+ if (alacarte.phase === 'notPurchasable') {
185
+ return (_jsxs(_Fragment, { children: [alacarteDebug, _jsx(Row, { className: "checkout__container bg-light-200", children: _jsx(Col, { xs: 12, children: _jsx(Alert, { variant: "danger", icon: ErrorIcon, children: alacarte.error }) }) })] }));
186
+ }
187
+ const isAlreadyOwned = alacarte.isAlreadyOwned;
188
+ return (_jsxs(_Fragment, { children: [alacarteDebug, _jsxs(Row, { className: "checkout__container bg-light-200", children: [_jsx(CountryUnavailableModal, { isOpen: isBillingCountryBlocked, homeUrl: homeUrl }), _jsx(Col, { xs: 12, className: "d-lg-none", children: _jsx("h1", { className: "font-weight-bold text-primary-900", children: "Checkout" }) }), _jsx(Col, { xs: 12, className: isAlreadyOwned ? 'checkout__owned-overlay' : '', children: _jsxs(Row, { className: "flex-column-reverse gap-5 flex-lg-row", children: [_jsx(Col, { xs: 12, lg: 7, xxl: 9, className: "payment__options", children: _jsxs("div", { children: [_jsx("h1", { className: "font-weight-bold text-primary-900 d-none d-lg-block mb-4", children: "Checkout" }), isAlreadyOwned && (_jsxs(Alert, { variant: "danger", icon: ErrorIcon, className: "checkout__already-owned-alert mb-3", "data-testid": "already-owned-alert", children: [_jsx("p", { className: "mb-3", children: formatMessage(((_m = alacarte.selector) === null || _m === void 0 ? void 0 : _m.kind) === 'program'
189
+ ? messages.alreadyPaidProgram
190
+ : messages.alreadyPaidCourse) }), _jsxs("div", { className: "d-flex align-items-center justify-content-end gap-3 flex-wrap", children: [orderHistoryUrl && (_jsx("a", { href: orderHistoryUrl, className: "text-gray-900 font-weight-bold", children: formatMessage(messages.viewOrderHistory) })), _jsx(Button, { variant: "brand", className: "rounded-pill", onClick: handleStartCourse, children: formatMessage(messages.goToCourse) })] })] })), c.error && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: c.clearError, children: c.error })), alacarte.placeOrderError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearPlaceOrderError, className: "mb-3", children: alacarte.placeOrderError })), alacarte.couponError && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, dismissible: true, onClose: alacarte.clearCouponError, className: "mb-3", "data-testid": "coupon-error-alert", children: alacarte.couponError })), !alacarte.priceAccepted && isAlacarteReady && ((_o = alacarte.line) === null || _o === void 0 ? void 0 : _o.amountDue) && (_jsx(Alert, { variant: "info", className: "mb-3", "data-testid": "price-accept-notice", children: formatMessage(messages.priceChangedNotice, {
181
191
  amount: alacarte.line.amountDue.amount.toFixed(2),
182
192
  currency: alacarte.line.amountDue.currency,
183
- }) })), showForm && (_jsxs(_Fragment, { children: [c.phase === 'failed' && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", children: failedMessage
193
+ }) })), showForm && (_jsxs(_Fragment, { children: [showValidationBanner && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", children: formatMessage(messages.validationBanner) })), c.phase === 'failed' && (_jsx(Alert, { variant: "danger", icon: ErrorIcon, className: "mb-3", children: failedMessage
184
194
  || 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, {
185
195
  code: appliedCouponCode,
186
196
  percent: appliedDiscount.percent,
187
- })] })), _jsx(PaymentForm, { billing: c.billing, setField: c.setField, numberMountRef: c.numberMountRef, expiryMountRef: c.expiryMountRef, cvcMountRef: c.cvcMountRef, cardError: c.cardError, stripeReady: c.stripeReady, sessionReady: c.sessionReady, submitting: isAlacarteReady
197
+ })] })), _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
188
198
  ? (alacarte.placingOrder || alacarte.awaitingPlacedOrder)
189
199
  : c.processingSubscription, onPlaceOrder: isAlacarteReady
190
200
  ? () => {
@@ -196,7 +206,7 @@ const Checkout = (_a) => {
196
206
  confirmCardPayment: c.confirmCardPayment,
197
207
  });
198
208
  }
199
- : c.placeOrder, trialEnd: selectedCycle === 'monthly' ? displayEnd : undefined, priceToShow: null, cycleToShow: selectedCycle === 'monthly' ? 'monthly' : 'annual', userCountry: c.userCountry, geolocationUrl: props.geolocationUrl, alacarteLine: alacarte.line, stripe: c.stripe, expressCountry: c.billing.country || c.userCountry || 'US', onExpressPayment: isAlacarteReady ? handleExpressPayment : undefined })] })), c.phase === 'success' && (_jsx(SuccessScreen, { subscriptionBiId: ((_l = c.subscriptionDetails) === null || _l === void 0 ? void 0 : _l.biId) || '', cardLast4: ((_m = c.subscriptionDetails) === null || _m === void 0 ? void 0 : _m.cardLast4) || '', purchaseDate: displayStart, courseLabel: courseLabel, onFindCourse: handleStartCourse })), c.phase === 'blocked' && (_jsx(BlockedScreen, { detail: c.lastComment }))] }) }), _jsx(Col, { xs: 12, lg: 5, xxl: 3, className: "payment__summary", children: c.phase === 'success' ? (_jsx(EnrollmentSummary, { course: c.course, onStartCourse: handleStartCourse })) : (_jsx(CartSummary, { defaultCycle: selectedCycle, onCycleChange: c.processingSubscription ? undefined : c.setCycle, course: courseForSummary, alacarteLine: alacarte.line, programDetail: alacarteProgramDetail, promoCode: isAlacarteReady ? {
209
+ : c.placeOrder, onValidationError: setShowValidationBanner, trialEnd: selectedCycle === 'monthly' ? displayEnd : undefined, priceToShow: null, cycleToShow: selectedCycle === 'monthly' ? 'monthly' : 'annual', userCountry: c.userCountry, geolocationUrl: props.geolocationUrl, alacarteLine: alacarte.line, stripe: c.stripe, expressCountry: c.billing.country || c.userCountry || 'US', onExpressPayment: isAlacarteReady ? handleExpressPayment : undefined })] })), c.phase === 'success' && (_jsx(SuccessScreen, { subscriptionBiId: ((_p = c.subscriptionDetails) === null || _p === void 0 ? void 0 : _p.biId) || '', cardLast4: ((_q = c.subscriptionDetails) === null || _q === void 0 ? void 0 : _q.cardLast4) || '', purchaseDate: displayStart, courseLabel: courseLabel, onFindCourse: handleStartCourse })), c.phase === 'blocked' && (_jsx(BlockedScreen, { detail: c.lastComment }))] }) }), _jsx(Col, { xs: 12, lg: 5, xxl: 3, className: "payment__summary", children: c.phase === 'success' ? (_jsx(EnrollmentSummary, { course: c.course, onStartCourse: handleStartCourse })) : (_jsx(CartSummary, { defaultCycle: selectedCycle, onCycleChange: c.processingSubscription ? undefined : c.setCycle, course: courseForSummary, alacarteLine: alacarte.line, programDetail: alacarteProgramDetail, programName: alacarte.ownedProductName, promoCode: isAlacarteReady ? {
200
210
  value: promoCodeValue,
201
211
  onChange: (next) => {
202
212
  setPromoCodeValue(next);
@@ -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, 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 } 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 // 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.checkout;\n const appliedCouponCode = alacarte.checkout?.couponCode?.trim()\n ? alacarte.checkout.couponCode.trim()\n : null;\n const discountPercent = appliedDiscountPercent(alacarte.line);\n const appliedDiscount = appliedCouponCode && alacarte.line?.discount && 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 useEffect(() => {\n if (alacarte.checkout?.couponCode) {\n setPromoCodeValue(alacarte.checkout.couponCode);\n }\n }, [alacarte.checkout?.couponCode]);\n\n useEffect(() => {\n if (appliedCouponCode && discountPercent != null) {\n setAdvertisedOffer({ code: appliedCouponCode, percent: discountPercent });\n }\n }, [appliedCouponCode, 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\n await alacarte.placeOrderAsync({\n billing: {\n ...c.billing,\n country: c.billing.country || walletCountry || c.userCountry || '',\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 const alacarteCourseDetail: CourseDetail | null\n = alacarte.line?.kind === 'course' && alacarte.productDetail && 'maId' in alacarte.productDetail\n ? alacarte.productDetail\n : null;\n const courseForSummary = alacarteCourseDetail ?? c.course;\n\n const alacarteProgramDetail: ProgramDetail | null\n = alacarte.line?.kind === 'program' && 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 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 orderHistoryUrl={orderHistoryUrl ?? null}\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 === 'alreadyOwned' || alacarte.phase === 'noActiveCheckout') {\n return (\n <>\n {alacarteDebug}\n <AlacarteNotice messageId={alacarte.noticeMessageId!} />\n </>\n );\n }\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 <Col xs={12}>\n <Row className=\"flex-column-reverse gap-5 flex-lg-row\">\n {/* ── LEFT ── */}\n <Col xs={12} lg={7} xxl={9} className=\"payment__options\">\n <div>\n <h1 className=\"font-weight-bold text-primary-900 d-none d-lg-block mb-4\">\n Checkout\n </h1>\n {c.error && (\n <Alert\n variant=\"danger\"\n icon={ErrorIcon}\n dismissible\n onClose={c.clearError}\n >\n {c.error}\n </Alert>\n )}\n\n {alacarte.placeOrderError && (\n <Alert\n variant=\"warning\"\n icon={ErrorIcon}\n dismissible\n onClose={alacarte.clearPlaceOrderError}\n className=\"mb-3\"\n >\n {alacarte.placeOrderError}\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 {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 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 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 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 } 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 const appliedDiscount = appliedCouponCode && alacarte.line?.discount && 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 useEffect(() => {\n if (alacarte.checkout?.couponCode) {\n setPromoCodeValue(alacarte.checkout.couponCode);\n }\n }, [alacarte.checkout?.couponCode]);\n\n useEffect(() => {\n if (appliedCouponCode && discountPercent != null) {\n setAdvertisedOffer({ code: appliedCouponCode, percent: discountPercent });\n }\n }, [appliedCouponCode, 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\n await alacarte.placeOrderAsync({\n billing: {\n ...c.billing,\n country: c.billing.country || walletCountry || c.userCountry || '',\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 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 orderHistoryUrl={orderHistoryUrl ?? null}\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 if (alacarte.phase === 'notPurchasable') {\n return (\n <>\n {alacarteDebug}\n <Row className=\"checkout__container bg-light-200\">\n <Col xs={12}>\n <Alert variant=\"danger\" icon={ErrorIcon}>\n {alacarte.error}\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.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"]}
@@ -19,5 +19,30 @@ declare const messages: {
19
19
  defaultMessage: string;
20
20
  description: string;
21
21
  };
22
+ validationBanner: {
23
+ id: string;
24
+ defaultMessage: string;
25
+ description: string;
26
+ };
27
+ alreadyPaidCourse: {
28
+ id: string;
29
+ defaultMessage: string;
30
+ description: string;
31
+ };
32
+ alreadyPaidProgram: {
33
+ id: string;
34
+ defaultMessage: string;
35
+ description: string;
36
+ };
37
+ viewOrderHistory: {
38
+ id: string;
39
+ defaultMessage: string;
40
+ description: string;
41
+ };
42
+ goToCourse: {
43
+ id: string;
44
+ defaultMessage: string;
45
+ description: string;
46
+ };
22
47
  };
23
48
  export default messages;
@@ -20,6 +20,31 @@ const messages = defineMessages({
20
20
  defaultMessage: 'Dismiss',
21
21
  description: 'Closes the coupon-applied success alert',
22
22
  },
23
+ validationBanner: {
24
+ id: 'checkout.validationBanner',
25
+ defaultMessage: 'Please complete the required fields highlighted below.',
26
+ description: 'Error banner shown when required payment fields are not filled in',
27
+ },
28
+ alreadyPaidCourse: {
29
+ id: 'checkout.alreadyPaid.course',
30
+ defaultMessage: "You've already paid for this course. You haven't been charged again.",
31
+ description: 'Alert shown when the learner already owns the course',
32
+ },
33
+ alreadyPaidProgram: {
34
+ id: 'checkout.alreadyPaid.program',
35
+ defaultMessage: "You've already paid for this program. You haven't been charged again.",
36
+ description: 'Alert shown when the learner already owns the program',
37
+ },
38
+ viewOrderHistory: {
39
+ id: 'checkout.alreadyPaid.viewOrderHistory',
40
+ defaultMessage: 'View order history',
41
+ description: 'Link to order history on the already-paid alert',
42
+ },
43
+ goToCourse: {
44
+ id: 'checkout.alreadyPaid.goToCourse',
45
+ defaultMessage: 'Go to course',
46
+ description: 'Button to navigate to the course on the already-paid alert',
47
+ },
23
48
  });
24
49
  export default messages;
25
50
  //# sourceMappingURL=Messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Messages.js","sourceRoot":"","sources":["../../../src/components/Checkout/Messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,4BAA4B,EAAE;QAC5B,EAAE,EAAE,mDAAmD;QACvD,cAAc,EAAE,oFAAoF;QACpG,WAAW,EAAE,gCAAgC;KAC9C;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;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});\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,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,8 +1,14 @@
1
1
  import type { Ref } from 'react';
2
+ export interface PaymentFieldErrors {
3
+ number?: string;
4
+ expiry?: string;
5
+ cvc?: string;
6
+ }
2
7
  export interface PaymentFieldsProps {
3
8
  numberMountRef: Ref<HTMLDivElement>;
4
9
  expiryMountRef: Ref<HTMLDivElement>;
5
10
  cvcMountRef: Ref<HTMLDivElement>;
11
+ fieldErrors?: PaymentFieldErrors;
6
12
  }
7
- declare const PaymentFields: ({ numberMountRef, expiryMountRef, cvcMountRef, }: PaymentFieldsProps) => import("react/jsx-runtime").JSX.Element;
13
+ declare const PaymentFields: ({ numberMountRef, expiryMountRef, cvcMountRef, fieldErrors, }: PaymentFieldsProps) => import("react/jsx-runtime").JSX.Element;
8
14
  export default PaymentFields;
@@ -3,6 +3,11 @@ import { Form } from '@openedx/paragon';
3
3
  import { STRIPE_FIELD_STYLE } from '../../constants';
4
4
  import { CardBrands } from '../BrandMarks/BrandMarks';
5
5
  import creditCardCvc from './creditCardCvc.png';
6
- const PaymentFields = ({ numberMountRef, expiryMountRef, cvcMountRef, }) => (_jsx("div", { className: "payment--field", children: _jsxs("div", { className: "d-flex flex-column mb-3 gap-4", children: [_jsxs(Form.Group, { controlId: "cardNumber", className: "mb-0 flex-grow-1", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "Card number (16 digits)" }), _jsxs("div", { className: "form-control", style: STRIPE_FIELD_STYLE, children: [_jsx("div", { ref: numberMountRef, className: "flex-grow-1" }), _jsx(CardBrands, {})] })] }), _jsxs("div", { className: "d-flex gap-4", children: [_jsxs(Form.Group, { controlId: "cardExpiry", className: "card__expiry mb-0 w-50", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "Expiration (MM/YY)" }), _jsx("div", { className: "form-control", style: STRIPE_FIELD_STYLE, children: _jsx("div", { ref: expiryMountRef, className: "flex-grow-1" }) })] }), _jsxs(Form.Group, { controlId: "cardCvc", className: "card__cvc mb-0 w-50", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "CVC (3-4 digits)" }), _jsxs("div", { className: "form-control", style: STRIPE_FIELD_STYLE, children: [_jsx("div", { ref: cvcMountRef, className: "flex-grow-1" }), _jsx("img", { src: creditCardCvc, alt: "", width: 24, height: 24 })] })] })] })] }) }));
6
+ const FieldError = ({ message }) => {
7
+ if (!message)
8
+ return null;
9
+ return (_jsxs("div", { className: "payment--field__error", role: "alert", children: [_jsx("span", { className: "payment--field__error-icon", "aria-hidden": "true" }), message] }));
10
+ };
11
+ const PaymentFields = ({ numberMountRef, expiryMountRef, cvcMountRef, fieldErrors, }) => (_jsx("div", { className: "payment--field", children: _jsxs("div", { className: "d-flex flex-column mb-3 gap-4", children: [_jsxs(Form.Group, { controlId: "cardNumber", className: "mb-0 flex-grow-1", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "Card number (16 digits)" }), _jsxs("div", { className: `form-control${(fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.number) ? ' payment--field__input--error' : ''}`, style: STRIPE_FIELD_STYLE, children: [_jsx("div", { ref: numberMountRef, className: "flex-grow-1" }), _jsx(CardBrands, {})] }), _jsx(FieldError, { message: fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.number })] }), _jsxs("div", { className: "d-flex gap-4", children: [_jsxs(Form.Group, { controlId: "cardExpiry", className: "card__expiry mb-0 w-50", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "Expiration (MM/YY)" }), _jsx("div", { className: `form-control${(fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.expiry) ? ' payment--field__input--error' : ''}`, style: STRIPE_FIELD_STYLE, children: _jsx("div", { ref: expiryMountRef, className: "flex-grow-1" }) }), _jsx(FieldError, { message: fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.expiry })] }), _jsxs(Form.Group, { controlId: "cardCvc", className: "card__cvc mb-0 w-50", children: [_jsx(Form.Label, { className: "payment--field__label text-gray-900", children: "CVC (3-4 digits)" }), _jsxs("div", { className: `form-control${(fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.cvc) ? ' payment--field__input--error' : ''}`, style: STRIPE_FIELD_STYLE, children: [_jsx("div", { ref: cvcMountRef, className: "flex-grow-1" }), _jsx("img", { src: creditCardCvc, alt: "", width: 24, height: 24 })] }), _jsx(FieldError, { message: fieldErrors === null || fieldErrors === void 0 ? void 0 : fieldErrors.cvc })] })] })] }) }));
7
12
  export default PaymentFields;
8
13
  //# sourceMappingURL=PaymentFields.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentFields.js","sourceRoot":"","sources":["../../../src/components/PaymentFields/PaymentFields.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAQhD,MAAM,aAAa,GAAG,CAAC,EACrB,cAAc,EACd,cAAc,EACd,WAAW,GACQ,EAAE,EAAE,CAAC,CACxB,cAAK,SAAS,EAAC,gBAAgB,YAE7B,eAAK,SAAS,EAAC,+BAA+B,aAE5C,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,SAAS,EAAC,kBAAkB,aAC7D,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,wCAE9C,EACb,eAAK,SAAS,EAAC,cAAc,EAAC,KAAK,EAAE,kBAAkB,aACrD,cAAK,GAAG,EAAE,cAAc,EAAE,SAAS,EAAC,aAAa,GAAG,EACpD,KAAC,UAAU,KAAG,IACV,IACK,EAEb,eAAK,SAAS,EAAC,cAAc,aAE3B,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,SAAS,EAAC,wBAAwB,aACnE,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,mCAE9C,EACb,cAAK,SAAS,EAAC,cAAc,EAAC,KAAK,EAAE,kBAAkB,YACrD,cAAK,GAAG,EAAE,cAAc,EAAE,SAAS,EAAC,aAAa,GAAG,GAChD,IACK,EAGb,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,SAAS,EAAC,SAAS,EAAC,qBAAqB,aAC7D,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,iCAA8B,EACzF,eAAK,SAAS,EAAC,cAAc,EAAC,KAAK,EAAE,kBAAkB,aACrD,cAAK,GAAG,EAAE,WAAW,EAAE,SAAS,EAAC,aAAa,GAAG,EACjD,cAAK,GAAG,EAAE,aAAa,EAAE,GAAG,EAAC,EAAE,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAI,IACrD,IACK,IACT,IACF,GACF,CACP,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import React from 'react';\nimport type { Ref } from 'react';\nimport { Form } from '@openedx/paragon';\nimport { STRIPE_FIELD_STYLE } from '../../constants';\nimport { CardBrands } from '../BrandMarks/BrandMarks';\nimport creditCardCvc from './creditCardCvc.png';\n\nexport interface PaymentFieldsProps {\n numberMountRef: Ref<HTMLDivElement>,\n expiryMountRef: Ref<HTMLDivElement>,\n cvcMountRef: Ref<HTMLDivElement>,\n}\n\nconst PaymentFields = ({\n numberMountRef,\n expiryMountRef,\n cvcMountRef,\n}: PaymentFieldsProps) => (\n <div className=\"payment--field\">\n {/* Single-row wrapper on desktop, stacked on mobile */}\n <div className=\"d-flex flex-column mb-3 gap-4\">\n {/* Card number — grows to fill available space */}\n <Form.Group controlId=\"cardNumber\" className=\"mb-0 flex-grow-1\">\n <Form.Label className=\"payment--field__label text-gray-900\">\n Card number (16 digits)\n </Form.Label>\n <div className=\"form-control\" style={STRIPE_FIELD_STYLE}>\n <div ref={numberMountRef} className=\"flex-grow-1\" />\n <CardBrands />\n </div>\n </Form.Group>\n\n <div className=\"d-flex gap-4\">\n {/* Expiry — fixed width on desktop */}\n <Form.Group controlId=\"cardExpiry\" className=\"card__expiry mb-0 w-50\">\n <Form.Label className=\"payment--field__label text-gray-900\">\n Expiration (MM/YY)\n </Form.Label>\n <div className=\"form-control\" style={STRIPE_FIELD_STYLE}>\n <div ref={expiryMountRef} className=\"flex-grow-1\" />\n </div>\n </Form.Group>\n\n {/* CVC — fixed width on desktop */}\n <Form.Group controlId=\"cardCvc\" className=\"card__cvc mb-0 w-50\">\n <Form.Label className=\"payment--field__label text-gray-900\">CVC (3-4 digits)</Form.Label>\n <div className=\"form-control\" style={STRIPE_FIELD_STYLE}>\n <div ref={cvcMountRef} className=\"flex-grow-1\" />\n <img src={creditCardCvc} alt=\"\" width={24} height={24} />\n </div>\n </Form.Group>\n </div>\n </div>\n </div>\n);\n\nexport default PaymentFields;\n"]}
1
+ {"version":3,"file":"PaymentFields.js","sourceRoot":"","sources":["../../../src/components/PaymentFields/PaymentFields.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAehD,MAAM,UAAU,GAAG,CAAC,EAAE,OAAO,EAAwB,EAAE,EAAE;IACvD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CACL,eAAK,SAAS,EAAC,uBAAuB,EAAC,IAAI,EAAC,OAAO,aACjD,eAAM,SAAS,EAAC,4BAA4B,iBAAa,MAAM,GAAG,EACjE,OAAO,IACJ,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,EACrB,cAAc,EACd,cAAc,EACd,WAAW,EACX,WAAW,GACQ,EAAE,EAAE,CAAC,CACxB,cAAK,SAAS,EAAC,gBAAgB,YAE7B,eAAK,SAAS,EAAC,+BAA+B,aAE5C,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,SAAS,EAAC,kBAAkB,aAC7D,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,wCAE9C,EACb,eACE,SAAS,EAAE,eAAe,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,EAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAAE,EACtF,KAAK,EAAE,kBAAkB,aAEzB,cAAK,GAAG,EAAE,cAAc,EAAE,SAAS,EAAC,aAAa,GAAG,EACpD,KAAC,UAAU,KAAG,IACV,EACN,KAAC,UAAU,IAAC,OAAO,EAAE,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,GAAI,IACjC,EAEb,eAAK,SAAS,EAAC,cAAc,aAE3B,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,SAAS,EAAC,wBAAwB,aACnE,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,mCAE9C,EACb,cACE,SAAS,EAAE,eAAe,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,EAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAAE,EACtF,KAAK,EAAE,kBAAkB,YAEzB,cAAK,GAAG,EAAE,cAAc,EAAE,SAAS,EAAC,aAAa,GAAG,GAChD,EACN,KAAC,UAAU,IAAC,OAAO,EAAE,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,MAAM,GAAI,IACjC,EAGb,MAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,SAAS,EAAC,SAAS,EAAC,qBAAqB,aAC7D,KAAC,IAAI,CAAC,KAAK,IAAC,SAAS,EAAC,qCAAqC,iCAA8B,EACzF,eACE,SAAS,EAAE,eAAe,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,GAAG,EAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE,EAAE,EACnF,KAAK,EAAE,kBAAkB,aAEzB,cAAK,GAAG,EAAE,WAAW,EAAE,SAAS,EAAC,aAAa,GAAG,EACjD,cAAK,GAAG,EAAE,aAAa,EAAE,GAAG,EAAC,EAAE,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAI,IACrD,EACN,KAAC,UAAU,IAAC,OAAO,EAAE,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,GAAG,GAAI,IAC9B,IACT,IACF,GACF,CACP,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import React from 'react';\nimport type { Ref } from 'react';\nimport { Form } from '@openedx/paragon';\nimport { STRIPE_FIELD_STYLE } from '../../constants';\nimport { CardBrands } from '../BrandMarks/BrandMarks';\nimport creditCardCvc from './creditCardCvc.png';\n\nexport interface PaymentFieldErrors {\n number?: string,\n expiry?: string,\n cvc?: string,\n}\n\nexport interface PaymentFieldsProps {\n numberMountRef: Ref<HTMLDivElement>,\n expiryMountRef: Ref<HTMLDivElement>,\n cvcMountRef: Ref<HTMLDivElement>,\n fieldErrors?: PaymentFieldErrors,\n}\n\nconst FieldError = ({ message }: { message?: string }) => {\n if (!message) return null;\n return (\n <div className=\"payment--field__error\" role=\"alert\">\n <span className=\"payment--field__error-icon\" aria-hidden=\"true\" />\n {message}\n </div>\n );\n};\n\nconst PaymentFields = ({\n numberMountRef,\n expiryMountRef,\n cvcMountRef,\n fieldErrors,\n}: PaymentFieldsProps) => (\n <div className=\"payment--field\">\n {/* Single-row wrapper on desktop, stacked on mobile */}\n <div className=\"d-flex flex-column mb-3 gap-4\">\n {/* Card number — grows to fill available space */}\n <Form.Group controlId=\"cardNumber\" className=\"mb-0 flex-grow-1\">\n <Form.Label className=\"payment--field__label text-gray-900\">\n Card number (16 digits)\n </Form.Label>\n <div\n className={`form-control${fieldErrors?.number ? ' payment--field__input--error' : ''}`}\n style={STRIPE_FIELD_STYLE}\n >\n <div ref={numberMountRef} className=\"flex-grow-1\" />\n <CardBrands />\n </div>\n <FieldError message={fieldErrors?.number} />\n </Form.Group>\n\n <div className=\"d-flex gap-4\">\n {/* Expiry — fixed width on desktop */}\n <Form.Group controlId=\"cardExpiry\" className=\"card__expiry mb-0 w-50\">\n <Form.Label className=\"payment--field__label text-gray-900\">\n Expiration (MM/YY)\n </Form.Label>\n <div\n className={`form-control${fieldErrors?.expiry ? ' payment--field__input--error' : ''}`}\n style={STRIPE_FIELD_STYLE}\n >\n <div ref={expiryMountRef} className=\"flex-grow-1\" />\n </div>\n <FieldError message={fieldErrors?.expiry} />\n </Form.Group>\n\n {/* CVC — fixed width on desktop */}\n <Form.Group controlId=\"cardCvc\" className=\"card__cvc mb-0 w-50\">\n <Form.Label className=\"payment--field__label text-gray-900\">CVC (3-4 digits)</Form.Label>\n <div\n className={`form-control${fieldErrors?.cvc ? ' payment--field__input--error' : ''}`}\n style={STRIPE_FIELD_STYLE}\n >\n <div ref={cvcMountRef} className=\"flex-grow-1\" />\n <img src={creditCardCvc} alt=\"\" width={24} height={24} />\n </div>\n <FieldError message={fieldErrors?.cvc} />\n </Form.Group>\n </div>\n </div>\n </div>\n);\n\nexport default PaymentFields;\n"]}
@@ -59,5 +59,10 @@ declare const messages: {
59
59
  defaultMessage: string;
60
60
  description: string;
61
61
  };
62
+ fieldRequired: {
63
+ id: string;
64
+ defaultMessage: string;
65
+ description: string;
66
+ };
62
67
  };
63
68
  export default messages;
@@ -63,6 +63,11 @@ const messages = defineMessages({
63
63
  defaultMessage: 'Select your country',
64
64
  description: 'Placeholder option shown before a country is selected',
65
65
  },
66
+ fieldRequired: {
67
+ id: 'checkout.paymentForm.fieldRequired',
68
+ defaultMessage: 'This field is required',
69
+ description: 'Error text shown below a required field that is empty',
70
+ },
66
71
  });
67
72
  export default messages;
68
73
  //# sourceMappingURL=Messages.js.map