@edx/frontend-app-subscription-checkout 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/LICENSE +661 -0
  2. package/README.rst +235 -0
  3. package/dist/Main.d.ts +3 -0
  4. package/dist/Main.js +15 -0
  5. package/dist/Main.js.map +1 -0
  6. package/dist/app.d.ts +3 -0
  7. package/dist/app.js +13 -0
  8. package/dist/app.js.map +1 -0
  9. package/dist/checkoutPage/CheckoutPage.d.ts +3 -0
  10. package/dist/checkoutPage/CheckoutPage.js +30 -0
  11. package/dist/checkoutPage/CheckoutPage.js.map +1 -0
  12. package/dist/components/BrandMarks/BrandMarks.d.ts +3 -0
  13. package/dist/components/BrandMarks/BrandMarks.js +9 -0
  14. package/dist/components/BrandMarks/BrandMarks.js.map +1 -0
  15. package/dist/components/CartSummary/CartSummary.d.ts +21 -0
  16. package/dist/components/CartSummary/CartSummary.js +30 -0
  17. package/dist/components/CartSummary/CartSummary.js.map +1 -0
  18. package/dist/components/CartSummary/Messages.d.ts +73 -0
  19. package/dist/components/CartSummary/Messages.js +76 -0
  20. package/dist/components/CartSummary/Messages.js.map +1 -0
  21. package/dist/components/Checkout/Checkout.d.ts +4 -0
  22. package/dist/components/Checkout/Checkout.js +40 -0
  23. package/dist/components/Checkout/Checkout.js.map +1 -0
  24. package/dist/components/CheckoutGate/CheckoutGate.d.ts +7 -0
  25. package/dist/components/CheckoutGate/CheckoutGate.js +35 -0
  26. package/dist/components/CheckoutGate/CheckoutGate.js.map +1 -0
  27. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.d.ts +9 -0
  28. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js +31 -0
  29. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js.map +1 -0
  30. package/dist/components/CourseEnrollmentCard/Messages.d.ts +33 -0
  31. package/dist/components/CourseEnrollmentCard/Messages.js +35 -0
  32. package/dist/components/CourseEnrollmentCard/Messages.js.map +1 -0
  33. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.d.ts +13 -0
  34. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js +11 -0
  35. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js.map +1 -0
  36. package/dist/components/EnrollmentSummary/EnrollmentSummary.d.ts +15 -0
  37. package/dist/components/EnrollmentSummary/EnrollmentSummary.js +21 -0
  38. package/dist/components/EnrollmentSummary/EnrollmentSummary.js.map +1 -0
  39. package/dist/components/EnrollmentSummary/Messages.d.ts +33 -0
  40. package/dist/components/EnrollmentSummary/Messages.js +35 -0
  41. package/dist/components/EnrollmentSummary/Messages.js.map +1 -0
  42. package/dist/components/PaymentFields/PaymentFields.d.ts +9 -0
  43. package/dist/components/PaymentFields/PaymentFields.js +7 -0
  44. package/dist/components/PaymentFields/PaymentFields.js.map +1 -0
  45. package/dist/components/PaymentForm/Messages.d.ts +88 -0
  46. package/dist/components/PaymentForm/Messages.js +95 -0
  47. package/dist/components/PaymentForm/Messages.js.map +1 -0
  48. package/dist/components/PaymentForm/PaymentForm.d.ts +21 -0
  49. package/dist/components/PaymentForm/PaymentForm.js +69 -0
  50. package/dist/components/PaymentForm/PaymentForm.js.map +1 -0
  51. package/dist/components/StatusScreens/Messages.d.ts +103 -0
  52. package/dist/components/StatusScreens/Messages.js +108 -0
  53. package/dist/components/StatusScreens/Messages.js.map +1 -0
  54. package/dist/components/StatusScreens/StatusScreens.d.ts +23 -0
  55. package/dist/components/StatusScreens/StatusScreens.js +25 -0
  56. package/dist/components/StatusScreens/StatusScreens.js.map +1 -0
  57. package/dist/constants.d.ts +59 -0
  58. package/dist/constants.js +276 -0
  59. package/dist/constants.js.map +1 -0
  60. package/dist/data/hooks/keys.d.ts +14 -0
  61. package/dist/data/hooks/keys.js +15 -0
  62. package/dist/data/hooks/keys.js.map +1 -0
  63. package/dist/data/hooks/useCheckout.d.ts +57 -0
  64. package/dist/data/hooks/useCheckout.js +249 -0
  65. package/dist/data/hooks/useCheckout.js.map +1 -0
  66. package/dist/data/hooks/useCheckoutGate.d.ts +15 -0
  67. package/dist/data/hooks/useCheckoutGate.js +39 -0
  68. package/dist/data/hooks/useCheckoutGate.js.map +1 -0
  69. package/dist/data/hooks/useCheckoutMutations.d.ts +16 -0
  70. package/dist/data/hooks/useCheckoutMutations.js +131 -0
  71. package/dist/data/hooks/useCheckoutMutations.js.map +1 -0
  72. package/dist/data/hooks/useCheckoutQueries.d.ts +30 -0
  73. package/dist/data/hooks/useCheckoutQueries.js +97 -0
  74. package/dist/data/hooks/useCheckoutQueries.js.map +1 -0
  75. package/dist/data/services/subs/urls.d.ts +2 -0
  76. package/dist/data/services/subs/urls.js +4 -0
  77. package/dist/data/services/subs/urls.js.map +1 -0
  78. package/dist/i18n/index.d.ts +1 -0
  79. package/dist/i18n/index.js +2 -0
  80. package/dist/i18n/index.js.map +1 -0
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +3 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/messages.d.ts +8 -0
  85. package/dist/messages.js +10 -0
  86. package/dist/messages.js.map +1 -0
  87. package/dist/routes.d.ts +18 -0
  88. package/dist/routes.js +67 -0
  89. package/dist/routes.js.map +1 -0
  90. package/dist/slots/ExampleSlot/ExampleSlot.d.ts +3 -0
  91. package/dist/slots/ExampleSlot/ExampleSlot.js +6 -0
  92. package/dist/slots/ExampleSlot/ExampleSlot.js.map +1 -0
  93. package/dist/slots.d.ts +3 -0
  94. package/dist/slots.js +7 -0
  95. package/dist/slots.js.map +1 -0
  96. package/dist/style.scss +14 -0
  97. package/dist/styles/components/brandMarks.scss +54 -0
  98. package/dist/styles/components/cartSummary.scss +18 -0
  99. package/dist/styles/components/checkout.scss +29 -0
  100. package/dist/styles/components/checkoutStepper.scss +9 -0
  101. package/dist/styles/components/courseEnrollmentCard.scss +38 -0
  102. package/dist/styles/components/edxUnlimitedBanner.scss +138 -0
  103. package/dist/styles/components/enrollmentSummary.scss +13 -0
  104. package/dist/styles/components/paymentFields.scss +15 -0
  105. package/dist/styles/components/paymentForm.scss +105 -0
  106. package/dist/styles/components/statusScreens.scss +29 -0
  107. package/dist/styles/components/successScreen.scss +0 -0
  108. package/dist/types.d.ts +222 -0
  109. package/dist/types.js +2 -0
  110. package/dist/types.js.map +1 -0
  111. package/dist/utils/auth.d.ts +7 -0
  112. package/dist/utils/auth.js +28 -0
  113. package/dist/utils/auth.js.map +1 -0
  114. package/dist/utils/billingDetails.d.ts +30 -0
  115. package/dist/utils/billingDetails.js +47 -0
  116. package/dist/utils/billingDetails.js.map +1 -0
  117. package/dist/utils/bootstrapApi.d.ts +20 -0
  118. package/dist/utils/bootstrapApi.js +142 -0
  119. package/dist/utils/bootstrapApi.js.map +1 -0
  120. package/dist/utils/cartApi.d.ts +16 -0
  121. package/dist/utils/cartApi.js +118 -0
  122. package/dist/utils/cartApi.js.map +1 -0
  123. package/dist/utils/checkout.d.ts +6 -0
  124. package/dist/utils/checkout.js +28 -0
  125. package/dist/utils/checkout.js.map +1 -0
  126. package/dist/utils/fetchActiveSubscriptions.d.ts +4 -0
  127. package/dist/utils/fetchActiveSubscriptions.js +36 -0
  128. package/dist/utils/fetchActiveSubscriptions.js.map +1 -0
  129. package/dist/utils/fetchBillingPlans.d.ts +2 -0
  130. package/dist/utils/fetchBillingPlans.js +48 -0
  131. package/dist/utils/fetchBillingPlans.js.map +1 -0
  132. package/dist/utils/graphqlClient.d.ts +16 -0
  133. package/dist/utils/graphqlClient.js +39 -0
  134. package/dist/utils/graphqlClient.js.map +1 -0
  135. package/dist/utils/index.d.ts +3 -0
  136. package/dist/utils/index.js +17 -0
  137. package/dist/utils/index.js.map +1 -0
  138. package/dist/utils/provision.d.ts +25 -0
  139. package/dist/utils/provision.js +95 -0
  140. package/dist/utils/provision.js.map +1 -0
  141. package/dist/utils/queries.d.ts +35 -0
  142. package/dist/utils/queries.js +168 -0
  143. package/dist/utils/queries.js.map +1 -0
  144. package/dist/utils/stripe.d.ts +7 -0
  145. package/dist/utils/stripe.js +43 -0
  146. package/dist/utils/stripe.js.map +1 -0
  147. package/dist/widgets/ExampleHeader/app.d.ts +3 -0
  148. package/dist/widgets/ExampleHeader/app.js +19 -0
  149. package/dist/widgets/ExampleHeader/app.js.map +1 -0
  150. package/dist/widgets/ExampleHeader/index.d.ts +1 -0
  151. package/dist/widgets/ExampleHeader/index.js +2 -0
  152. package/dist/widgets/ExampleHeader/index.js.map +1 -0
  153. package/package.json +85 -0
package/dist/slots.js ADDED
@@ -0,0 +1,7 @@
1
+ var _a;
2
+ import { exampleHeaderApp } from './widgets/ExampleHeader';
3
+ const slots = [
4
+ ...((_a = exampleHeaderApp.slots) !== null && _a !== void 0 ? _a : []),
5
+ ];
6
+ export default slots;
7
+ //# sourceMappingURL=slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.js","sourceRoot":"","sources":["../src/slots.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,KAAK,GAAoB;IAC7B,GAAG,CAAC,MAAA,gBAAgB,CAAC,KAAK,mCAAI,EAAE,CAAC;CAClC,CAAC;AAEF,eAAe,KAAK,CAAC","sourcesContent":["import { SlotOperation } from '@openedx/frontend-base';\n\nimport { exampleHeaderApp } from './widgets/ExampleHeader';\n\nconst slots: SlotOperation[] = [\n ...(exampleHeaderApp.slots ?? []),\n];\n\nexport default slots;\n"]}
@@ -0,0 +1,14 @@
1
+ @use "@openedx/paragon/styles/css/core/custom-media-breakpoints.css";
2
+
3
+
4
+ //components
5
+ @use "./styles/components/checkout.scss";
6
+ @use "./styles/components/enrollmentSummary.scss";
7
+ @use "./styles/components/paymentForm.scss";
8
+ @use "./styles/components/checkoutStepper.scss";
9
+ @use "./styles/components/paymentFields.scss";
10
+ @use "./styles/components/brandMarks.scss";
11
+ @use "./styles/components/statusScreens.scss";
12
+ @use "./styles/components/edxUnlimitedBanner.scss";
13
+ @use "./styles/components/cartSummary.scss";
14
+ @use "./styles/components/courseEnrollmentCard.scss";
@@ -0,0 +1,54 @@
1
+ .brand-marks {
2
+ &__card-brands {
3
+ display: flex;
4
+ align-items: center;
5
+ flex-shrink: 0;
6
+ gap: 4px;
7
+ }
8
+
9
+ &__paypal {
10
+ font-family: Arial, sans-serif;
11
+ font-weight: 700;
12
+ font-style: italic;
13
+ font-size: 1.05rem;
14
+ }
15
+
16
+ &__paypal-pay {
17
+ color: #003087;
18
+ }
19
+
20
+ &__paypal-pal {
21
+ color: #009cde;
22
+ }
23
+
24
+ &__edx-logo {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ flex-shrink: 0;
29
+ width: 56px;
30
+ height: 40px;
31
+ border-radius: 6px;
32
+ background: #1f1f1f;
33
+ line-height: 1;
34
+ margin-right: 0.75rem;
35
+ }
36
+
37
+ &__edx-logo-text {
38
+ text-align: center;
39
+ }
40
+
41
+ &__edx-logo-edx {
42
+ color: #fff;
43
+ font-weight: 800;
44
+ font-size: 0.8rem;
45
+ letter-spacing: -0.02em;
46
+ }
47
+
48
+ &__edx-logo-unlimited {
49
+ color: #b1c2ff;
50
+ font-size: 0.5rem;
51
+ font-weight: 600;
52
+ margin-top: 1px;
53
+ }
54
+ }
@@ -0,0 +1,18 @@
1
+ // styles/components/cartSummary.scss
2
+
3
+ .cart-summary {
4
+ // No background — inherits the page background (off-white in the design)
5
+ background: transparent;
6
+
7
+ &__stats {
8
+ display: flex;
9
+ gap: 1.5rem;
10
+ margin-top: 1rem;
11
+ }
12
+
13
+ &__stat {
14
+ display: flex;
15
+ align-items: center;
16
+ gap: 0.5rem;
17
+ }
18
+ }
@@ -0,0 +1,29 @@
1
+ div.checkout__container {
2
+ padding-inline: 1.125rem; /* 18px */
3
+ padding-block: 3rem; /* 48px */
4
+ div.payment__options {
5
+ > div {
6
+ padding: 32px;
7
+ background-color: white;
8
+ }
9
+ }
10
+ }
11
+
12
+ @media (--pgn-size-breakpoint-min-width-lg) {
13
+ div.checkout__container {
14
+ padding:0;
15
+ div.payment__options {
16
+ background-color: var(--pgn-color-light-100);
17
+ > div {
18
+ padding: 32px 32px 64px 32px;
19
+ background-color: transparent;
20
+ }
21
+ }
22
+ div.payment__summary {
23
+ padding: 48px 48px 32px 48px;
24
+ }
25
+ div.gap-5 {
26
+ gap: 0 !important;
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,9 @@
1
+ .checkout__stepper {
2
+ > div {
3
+ padding:0;
4
+
5
+ ul.pgn__stepper-header-step-list {
6
+ justify-content: flex-start;
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,38 @@
1
+ .course-enrollment-card {
2
+ margin-top: 1.25rem;
3
+ padding: 1rem;
4
+ background: var(--pgn-color-white, #fff);
5
+ border: 1px solid var(--pgn-color-light-400, #e5e5e5);
6
+ border-radius: var(--pgn-size-border-radius-base, 0.375rem);
7
+
8
+ &__image {
9
+ display: block;
10
+ width: 4.5rem;
11
+ height: 3.25rem;
12
+ object-fit: cover;
13
+ border-radius: 0.25rem;
14
+ background: var(--pgn-color-light-300, #f2f2f2);
15
+
16
+ &--placeholder {
17
+ background:
18
+ linear-gradient(
19
+ to top right,
20
+ transparent calc(50% - 1px),
21
+ var(--pgn-color-light-500, #c2c2c2) 50%,
22
+ transparent calc(50% + 1px)
23
+ ),
24
+ linear-gradient(
25
+ to top left,
26
+ transparent calc(50% - 1px),
27
+ var(--pgn-color-light-500, #c2c2c2) 50%,
28
+ transparent calc(50% + 1px)
29
+ ),
30
+ var(--pgn-color-light-300, #f2f2f2);
31
+ }
32
+ }
33
+
34
+ &__copy {
35
+ color: var(--pgn-color-gray-900, #212529);
36
+ line-height: 1.4;
37
+ }
38
+ }
@@ -0,0 +1,138 @@
1
+
2
+ .edx-banner {
3
+ background: #0a1628;
4
+ border-radius: 10px;
5
+ overflow: hidden;
6
+ display: flex;
7
+ align-items: stretch;
8
+ min-height: 120px;
9
+ position: relative;
10
+
11
+ &__content {
12
+ flex: 1 1 0;
13
+ padding: 28px 32px 28px 28px;
14
+ display: flex;
15
+ flex-direction: column;
16
+ justify-content: center;
17
+ gap: 10px;
18
+ z-index: 1;
19
+ }
20
+
21
+ &__eyebrow {
22
+ display: flex;
23
+ align-items: center;
24
+ }
25
+
26
+ &__headline {
27
+ margin: 0;
28
+ color: #fff;
29
+ font-size: clamp(1.1rem, 2.2vw, 1.55rem);
30
+ font-weight: 700;
31
+ line-height: 1.25;
32
+ letter-spacing: -0.01em;
33
+ }
34
+
35
+ &__body {
36
+ margin: 0;
37
+ color: rgba(255, 255, 255, 0.78);
38
+ font-size: clamp(0.78rem, 1.3vw, 0.88rem);
39
+ line-height: 1.55;
40
+ max-width: 540px;
41
+ }
42
+
43
+ &__cta-wrapper {
44
+ margin-top: 4px;
45
+ }
46
+
47
+ &__cta {
48
+ display: inline-block;
49
+ background: #e2522a;
50
+ color: #fff;
51
+ font-weight: 700;
52
+ font-size: 0.82rem;
53
+ padding: 9px 20px;
54
+ border-radius: 6px;
55
+ text-decoration: none;
56
+ letter-spacing: 0.01em;
57
+ transition: background 0.15s;
58
+ white-space: nowrap;
59
+
60
+ &:hover {
61
+ background: #c94420;
62
+ color: #fff;
63
+ text-decoration: none;
64
+ }
65
+ }
66
+
67
+ &__bullet {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ width: 28px;
72
+ height: 28px;
73
+ border-radius: 50%;
74
+ background: rgba(255, 255, 255, 0.15);
75
+ flex-shrink: 0;
76
+ margin-right: 10px;
77
+ }
78
+
79
+ &__badge {
80
+ display: inline-flex;
81
+ align-items: center;
82
+ gap: 0;
83
+ vertical-align: middle;
84
+ position: relative;
85
+ top: -2px;
86
+ }
87
+
88
+ &__badge-edx {
89
+ background: #fff;
90
+ border-radius: 4px 0 0 4px;
91
+ padding: 2px 5px 2px 6px;
92
+ font-weight: 800;
93
+ font-size: 0.78em;
94
+ letter-spacing: -0.02em;
95
+ color: #000;
96
+ line-height: 1.15;
97
+ font-style: normal;
98
+ }
99
+
100
+ &__badge-unlimited {
101
+ background: #000;
102
+ border-radius: 0 4px 4px 0;
103
+ padding: 2px 6px 2px 4px;
104
+ font-weight: 600;
105
+ font-size: 0.64em;
106
+ letter-spacing: 0.02em;
107
+ color: #c5b8ff;
108
+ line-height: 1.15;
109
+ font-style: normal;
110
+ text-transform: lowercase;
111
+ }
112
+
113
+ &__photo {
114
+ flex-shrink: 0;
115
+ width: clamp(120px, 22%, 240px);
116
+ position: relative;
117
+ overflow: hidden;
118
+
119
+ img {
120
+ position: absolute;
121
+ inset: 0;
122
+ width: 100%;
123
+ height: 100%;
124
+ object-fit: cover;
125
+ object-position: center top;
126
+ }
127
+ }
128
+
129
+
130
+ &__placeholder {
131
+ flex-shrink: 0;
132
+ width: clamp(100px, 20%, 200px);
133
+ background: rgba(255, 255, 255, 0.06);
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ }
138
+ }
@@ -0,0 +1,13 @@
1
+ .enrolled__banner {
2
+ div:first-child {
3
+ border-top-left-radius: var(--pgn-size-border-radius-base);
4
+ border-top-right-radius: var(--pgn-size-border-radius-base);
5
+ }
6
+
7
+ div:last-child {
8
+ border: 1px solid var(--pgn-color-light-400);
9
+ border-top: 0;
10
+ border-bottom-left-radius: var(--pgn-size-border-radius-base);
11
+ border-bottom-right-radius: var(--pgn-size-border-radius-base);
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ .payment--field {
2
+ .card__expiry,
3
+ .card__cvc {
4
+ width: 10.75rem;
5
+ }
6
+
7
+ .form-control {
8
+ border-radius: 5px;
9
+ border: 1px solid #E6E6E6;
10
+ background: #FFF;
11
+
12
+ /* default/box-shadow-default */
13
+ box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.02), 0 1px 1px 0 rgba(0, 0, 0, 0.03);
14
+ }
15
+ }
@@ -0,0 +1,105 @@
1
+ // styles/components/paymentForm.scss
2
+
3
+ .payment-form {
4
+ &__heading {
5
+ font-size: 1.1rem;
6
+ }
7
+
8
+ &__help {
9
+ a {
10
+ text-decoration: underline;
11
+ text-underline-offset: 0.2rem;
12
+ }
13
+ }
14
+
15
+ // ── Payment method accordion ─────────────────────────────────────────────
16
+
17
+ &__method {
18
+ border-radius: 8px;
19
+ border: 1px solid #E7E9EF;
20
+ background: #FFF;
21
+ overflow: hidden;
22
+ background: #F6F8FA;
23
+ &--selected {
24
+ background-color: white;
25
+ }
26
+ }
27
+
28
+ // Header row: radio + icon(s) + name — full-width clickable label
29
+ &__method-header {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: 0.6rem;
33
+ padding: 0.9rem 1rem;
34
+ margin: 0;
35
+ cursor: pointer;
36
+ width: 100%;
37
+ font-weight: 600;
38
+ font-size: 0.95rem;
39
+ }
40
+
41
+ &__radio {
42
+ flex-shrink: 0;
43
+ width: 1.1rem;
44
+ height: 1.1rem;
45
+ accent-color: #000000;
46
+ cursor: pointer;
47
+ }
48
+
49
+ &__method-name {
50
+ flex: 1;
51
+ }
52
+
53
+ // Expanded card panel — no extra heading, just fields
54
+ &__card-panel {
55
+ padding: 0 1rem 1rem;
56
+ background: #fff;
57
+ }
58
+
59
+ // Icon badges for Google Pay / PayPal
60
+ &__method-icon {
61
+ display: inline-flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ width: 1.5rem;
65
+ height: 1.5rem;
66
+ border-radius: 4px;
67
+ color: #fff;
68
+ font-weight: 800;
69
+ font-size: 0.7rem;
70
+ flex-shrink: 0;
71
+
72
+ &--gpay {
73
+ background: #4285f4;
74
+ }
75
+
76
+ &--paypal {
77
+ background: #003087;
78
+ }
79
+ }
80
+
81
+ .payment__field--country {
82
+ select {
83
+ border-radius: 5px;
84
+ border: 1px solid #E6E6E6;
85
+ box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.02), 0 1px 1px 0 rgba(0, 0, 0, 0.03);
86
+ }
87
+ }
88
+
89
+ // ── Submit button ────────────────────────────────────────────────────────
90
+ &__submit {
91
+ border-radius: 2rem;
92
+ font-weight: 700;
93
+ padding: 0.75rem 1.5rem;
94
+ }
95
+
96
+ &__terms {
97
+ line-height: 1.6;
98
+ }
99
+ }
100
+
101
+ @media (--pgn-size-breakpoint-min-width-lg) {
102
+ .payment-form {
103
+ padding: 32px;
104
+ }
105
+ }
@@ -0,0 +1,29 @@
1
+ // styles/components/successScreen.scss
2
+
3
+ .success-screen {
4
+ &__headline {
5
+ font-size: clamp(1.6rem, 3vw, 2.2rem);
6
+ color: #1a3a2a; // dark green as in design
7
+ }
8
+
9
+ &__ctas {
10
+ flex-wrap: wrap;
11
+ gap: 0.75rem;
12
+ }
13
+
14
+ &__cta-primary {
15
+ border-radius: 2rem;
16
+ font-weight: 700;
17
+ padding: 0.65rem 1.5rem;
18
+ }
19
+
20
+ &__benefits {
21
+ list-style: disc;
22
+ padding-left: 1.25rem;
23
+
24
+ li {
25
+ color: var(--gray-700, #495057);
26
+ line-height: 1.6;
27
+ }
28
+ }
29
+ }
File without changes
@@ -0,0 +1,222 @@
1
+ import type { Status, Phase } from './constants';
2
+ export type { Status, Phase };
3
+ export interface TwouCustomerContact {
4
+ email?: string;
5
+ }
6
+ export interface TwouCustomerParty {
7
+ paName: string;
8
+ indFirstName?: string;
9
+ indLastName?: string;
10
+ paContacts: {
11
+ edges: {
12
+ node: TwouCustomerContact;
13
+ }[];
14
+ };
15
+ }
16
+ export interface TwouCustomer {
17
+ uid: string;
18
+ parId: string;
19
+ parParty: TwouCustomerParty;
20
+ }
21
+ export type GqlRunner = (query: string, variables?: Record<string, unknown>, retry?: boolean) => Promise<any>;
22
+ export interface Cart {
23
+ biId: string;
24
+ uid: string;
25
+ }
26
+ export interface CartIds {
27
+ customerUid: string;
28
+ salableUid: string;
29
+ billingPlanUid: string;
30
+ }
31
+ export type BillingCycle = 'monthly' | 'annual';
32
+ export type BillingPeriod = 'MONTHLY' | 'ANNUAL' | 'QUARTERLY' | string;
33
+ export interface BillingPlanOwnershipModel {
34
+ uid: string;
35
+ omName: string;
36
+ }
37
+ export interface BillingPlan {
38
+ uid: string;
39
+ stripePriceId: string;
40
+ /** Price amount e.g. "39.99" */
41
+ amount: string;
42
+ /** Currency code e.g. "USD" */
43
+ currency: string;
44
+ isTemplate: boolean;
45
+ ownershipModel: BillingPlanOwnershipModel;
46
+ }
47
+ export interface SubscriptionDetails {
48
+ biId: string;
49
+ trialStart: string | null;
50
+ trialEnd: string | null;
51
+ renewalType: string | null;
52
+ cardLast4: string | null;
53
+ cardBrand: string | null;
54
+ stripePaymentMethodId: string | null;
55
+ planName: string | null;
56
+ }
57
+ export interface CurrentUserSubscriberResult {
58
+ isSubscriber: boolean;
59
+ subscriptionBiId: string | null;
60
+ status: string | null;
61
+ subscriptionStartDate: string | null;
62
+ currentPeriodEnd: string | null;
63
+ }
64
+ /** Course shown on checkout / post-checkout when arriving via ?course_run_key=. */
65
+ export interface CourseDetail {
66
+ maId: string;
67
+ maName: string;
68
+ maDescription: string | null;
69
+ tShortDescription: string | null;
70
+ imageUrl: string | null;
71
+ tCourseKey: string | null;
72
+ tBrandText: string | null;
73
+ tPrimarySubjectArea: string | null;
74
+ tLevelType: string | null;
75
+ tLanguage: string | null;
76
+ tPacingType: string | null;
77
+ tDurationLow: number | null;
78
+ tDurationHigh: number | null;
79
+ tDurationUnit: string | null;
80
+ tEffortLow: number | null;
81
+ tEffortHigh: number | null;
82
+ tEffortUnit: string | null;
83
+ tUrlCourse: string | null;
84
+ tB2cSubscriptionInclusion: boolean | null;
85
+ tHasOfacRestrictions: boolean | null;
86
+ tCatalogActive: boolean | null;
87
+ }
88
+ /** Returned by getBillingPlans — all available plans for the product. */
89
+ export interface BillingPlansResult {
90
+ plans: BillingPlan[];
91
+ }
92
+ /** Returned by getSalableUid — the product uid and its ownership models. */
93
+ export interface ProductInfo {
94
+ uid: string;
95
+ maName: string;
96
+ ownershipModels: {
97
+ uid: string;
98
+ omName: string;
99
+ }[];
100
+ }
101
+ export interface CartStatusResult {
102
+ status: Status | null;
103
+ stripeSubscriptionId: string | null;
104
+ lastComment: string;
105
+ }
106
+ export interface CartBillingAddress {
107
+ tFirstName: string;
108
+ tLastName: string;
109
+ upaLine1: string;
110
+ upaCity: string;
111
+ upaPostcode: string;
112
+ gadStateOrProvince: string;
113
+ gadCountry: {
114
+ iso2Code: string;
115
+ };
116
+ }
117
+ export interface UpdateCartItemArgs {
118
+ cartItemUid: string;
119
+ billingAddress?: CartBillingAddress;
120
+ paymentMethodId?: string;
121
+ }
122
+ /** Auto-renewal consent captured on TwouCart at checkout confirmation (SUBS-228). */
123
+ export interface CheckoutConsent {
124
+ /** Main auto-renewal checkbox — always required at submit. */
125
+ tConsentRecurring: boolean;
126
+ /** UK/CA resident checkbox; null when that checkbox is not shown. */
127
+ tConsentUkCa: boolean | null;
128
+ /** ISO-8601 timestamp when consent was captured. */
129
+ tConsentAt: string;
130
+ /** Exact disclosure text shown to the learner (audit trail). */
131
+ tConsentText: string;
132
+ }
133
+ export interface UpdateCartConsentArgs {
134
+ cartUid: string;
135
+ consent: CheckoutConsent;
136
+ }
137
+ export interface BillingInfo {
138
+ firstName: string;
139
+ lastName: string;
140
+ city: string;
141
+ zip: string;
142
+ country: string;
143
+ line1: string;
144
+ state: string;
145
+ }
146
+ export interface CheckoutClient {
147
+ gql: GqlRunner;
148
+ setToken: (token: string) => void;
149
+ createCart: (vars: CartIds) => Promise<Cart>;
150
+ getCartItem: (biId: string) => Promise<{
151
+ cartUid: string;
152
+ cartItemUid: string;
153
+ }>;
154
+ updateCartItem: (args: UpdateCartItemArgs) => Promise<void>;
155
+ updateCartConsent: (args: UpdateCartConsentArgs) => Promise<void>;
156
+ placeOrder: (cartUid: string) => Promise<unknown>;
157
+ getCartStatus: (biId: string) => Promise<CartStatusResult>;
158
+ findSubscriptionBiId: (biId: string) => Promise<SubscriptionDetails | null>;
159
+ getSalableUid: (maId: string) => Promise<ProductInfo>;
160
+ getBillingPlans: () => Promise<BillingPlansResult>;
161
+ getActiveSubscriptions: () => Promise<{
162
+ active: number;
163
+ }>;
164
+ isCurrentUserSubscriber: () => Promise<CurrentUserSubscriberResult | null>;
165
+ getCourseDetail: (courseKey: string) => Promise<CourseDetail | null>;
166
+ }
167
+ export interface DevAuth {
168
+ iamUrl: string;
169
+ clientId: string;
170
+ clientSecret: string;
171
+ }
172
+ export interface StripeElementChangeEvent {
173
+ error?: {
174
+ message?: string;
175
+ };
176
+ [key: string]: unknown;
177
+ }
178
+ export interface StripeElementLike {
179
+ mount: (node: HTMLElement) => void;
180
+ on: (event: string, handler: (e: StripeElementChangeEvent) => void) => void;
181
+ unmount?: () => void;
182
+ }
183
+ export interface StripeElementsLike {
184
+ create: (type: string, options?: Record<string, unknown>) => StripeElementLike;
185
+ }
186
+ export interface StripeError {
187
+ message?: string;
188
+ code?: string;
189
+ }
190
+ export interface PaymentMethodResult {
191
+ paymentMethod?: {
192
+ id: string;
193
+ };
194
+ error?: StripeError;
195
+ }
196
+ export interface ConfirmResult {
197
+ error?: StripeError;
198
+ setupIntent?: unknown;
199
+ paymentIntent?: unknown;
200
+ }
201
+ export interface CreatePaymentMethodParams {
202
+ type: 'card';
203
+ card: StripeElementLike;
204
+ billing_details?: Record<string, unknown>;
205
+ }
206
+ export interface StripeLike {
207
+ elements: () => StripeElementsLike;
208
+ createPaymentMethod: (params: CreatePaymentMethodParams) => Promise<PaymentMethodResult>;
209
+ confirmCardSetup: (clientSecret: string) => Promise<ConfirmResult>;
210
+ confirmCardPayment: (clientSecret: string) => Promise<ConfirmResult>;
211
+ }
212
+ declare global {
213
+ interface Window {
214
+ Stripe?: (publishableKey: string) => StripeLike;
215
+ }
216
+ }
217
+ export interface TrialDateRange {
218
+ /** e.g. "June 22, 2026" */
219
+ displayStart: string;
220
+ /** e.g. "June 29, 2026" */
221
+ displayEnd: string;
222
+ }