@edx/frontend-app-subscription-manage 1.3.2 → 1.5.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 (226) hide show
  1. package/dist/app.js +2 -2
  2. package/dist/app.js.map +1 -1
  3. package/dist/components/ActiveSubscription/ActiveSubscription.d.ts +7 -0
  4. package/dist/components/ActiveSubscription/ActiveSubscription.js +24 -0
  5. package/dist/components/ActiveSubscription/ActiveSubscription.js.map +1 -0
  6. package/dist/components/BecomeSubscriber/BecomeSubscriber.d.ts +7 -0
  7. package/dist/components/BecomeSubscriber/BecomeSubscriber.js +19 -0
  8. package/dist/components/BecomeSubscriber/BecomeSubscriber.js.map +1 -0
  9. package/dist/components/CancelConfirmation/CancelConfirmation.d.ts +12 -0
  10. package/dist/components/CancelConfirmation/CancelConfirmation.js +21 -0
  11. package/dist/components/CancelConfirmation/CancelConfirmation.js.map +1 -0
  12. package/dist/components/CancelSuccess/CancelSuccess.d.ts +7 -0
  13. package/dist/components/CancelSuccess/CancelSuccess.js +17 -0
  14. package/dist/components/CancelSuccess/CancelSuccess.js.map +1 -0
  15. package/dist/components/CanceledSubscription/CanceledSubscription.d.ts +13 -0
  16. package/dist/components/CanceledSubscription/CanceledSubscription.js +27 -0
  17. package/dist/components/CanceledSubscription/CanceledSubscription.js.map +1 -0
  18. package/dist/components/EnrolledCoursesList/EnrolledCoursesList.d.ts +8 -0
  19. package/dist/components/EnrolledCoursesList/EnrolledCoursesList.js +19 -0
  20. package/dist/components/EnrolledCoursesList/EnrolledCoursesList.js.map +1 -0
  21. package/dist/components/HelpFooter/HelpFooter.d.ts +3 -0
  22. package/dist/components/HelpFooter/HelpFooter.js +12 -0
  23. package/dist/components/HelpFooter/HelpFooter.js.map +1 -0
  24. package/dist/components/OrderHistoryHeader/OrderHistoryHeader.d.ts +3 -0
  25. package/dist/components/OrderHistoryHeader/OrderHistoryHeader.js +9 -0
  26. package/dist/components/OrderHistoryHeader/OrderHistoryHeader.js.map +1 -0
  27. package/dist/components/PaymentHistory/PaymentHistory.d.ts +10 -0
  28. package/dist/components/PaymentHistory/PaymentHistory.js +23 -0
  29. package/dist/components/PaymentHistory/PaymentHistory.js.map +1 -0
  30. package/dist/components/RenewSubscriptionModal/RenewSubscriptionModal.d.ts +17 -0
  31. package/dist/components/RenewSubscriptionModal/RenewSubscriptionModal.js +63 -0
  32. package/dist/components/RenewSubscriptionModal/RenewSubscriptionModal.js.map +1 -0
  33. package/dist/components/ResubscribeCard/ResubscribeCard.d.ts +9 -0
  34. package/dist/components/ResubscribeCard/ResubscribeCard.js +25 -0
  35. package/dist/components/ResubscribeCard/ResubscribeCard.js.map +1 -0
  36. package/dist/components/SubscriptionTabs/SubscriptionTabs.d.ts +8 -0
  37. package/dist/components/SubscriptionTabs/SubscriptionTabs.js +9 -0
  38. package/dist/components/SubscriptionTabs/SubscriptionTabs.js.map +1 -0
  39. package/dist/components/UpdatePaymentMethodModal/UpdatePaymentMethodModal.d.ts +9 -0
  40. package/dist/components/UpdatePaymentMethodModal/UpdatePaymentMethodModal.js +135 -0
  41. package/dist/components/UpdatePaymentMethodModal/UpdatePaymentMethodModal.js.map +1 -0
  42. package/dist/components/messages.d.ts +473 -0
  43. package/dist/components/messages.js +482 -0
  44. package/dist/components/messages.js.map +1 -0
  45. package/dist/constants.d.ts +14 -56
  46. package/dist/constants.js +23 -272
  47. package/dist/constants.js.map +1 -1
  48. package/dist/data/hooks/keys.d.ts +8 -13
  49. package/dist/data/hooks/keys.js +8 -13
  50. package/dist/data/hooks/keys.js.map +1 -1
  51. package/dist/data/hooks/useManageQueries.d.ts +37 -0
  52. package/dist/data/hooks/useManageQueries.js +206 -0
  53. package/dist/data/hooks/useManageQueries.js.map +1 -0
  54. package/dist/data/services/subs/urls.d.ts +2 -2
  55. package/dist/data/services/subs/urls.js.map +1 -1
  56. package/dist/data/services/subscription/cancelSubscription.d.ts +6 -0
  57. package/dist/data/services/subscription/cancelSubscription.js +31 -0
  58. package/dist/data/services/subscription/cancelSubscription.js.map +1 -0
  59. package/dist/data/services/subscription/getBillingPlans.d.ts +3 -0
  60. package/dist/{utils/fetchBillingPlans.js → data/services/subscription/getBillingPlans.js} +10 -21
  61. package/dist/data/services/subscription/getBillingPlans.js.map +1 -0
  62. package/dist/data/services/subscription/getIsCurrentUserSubscriber.d.ts +3 -0
  63. package/dist/data/services/subscription/getIsCurrentUserSubscriber.js +37 -0
  64. package/dist/data/services/subscription/getIsCurrentUserSubscriber.js.map +1 -0
  65. package/dist/data/services/subscription/getPaymentHistory.d.ts +6 -0
  66. package/dist/data/services/subscription/getPaymentHistory.js +65 -0
  67. package/dist/data/services/subscription/getPaymentHistory.js.map +1 -0
  68. package/dist/data/services/subscription/getSubscriptionEnrollments.d.ts +7 -0
  69. package/dist/data/services/subscription/getSubscriptionEnrollments.js +88 -0
  70. package/dist/data/services/subscription/getSubscriptionEnrollments.js.map +1 -0
  71. package/dist/data/services/subscription/getSubscriptionPaymentMethod.d.ts +8 -0
  72. package/dist/data/services/subscription/getSubscriptionPaymentMethod.js +42 -0
  73. package/dist/data/services/subscription/getSubscriptionPaymentMethod.js.map +1 -0
  74. package/dist/data/services/subscription/reactivateSubscription.d.ts +6 -0
  75. package/dist/data/services/subscription/reactivateSubscription.js +30 -0
  76. package/dist/data/services/subscription/reactivateSubscription.js.map +1 -0
  77. package/dist/data/services/subscription/updateSubscriptionPaymentMethod.d.ts +10 -0
  78. package/dist/data/services/subscription/updateSubscriptionPaymentMethod.js +31 -0
  79. package/dist/data/services/subscription/updateSubscriptionPaymentMethod.js.map +1 -0
  80. package/dist/icons/ExternalLinkIcon.d.ts +6 -0
  81. package/dist/icons/ExternalLinkIcon.js +18 -0
  82. package/dist/icons/ExternalLinkIcon.js.map +1 -0
  83. package/dist/icons/index.d.ts +1 -0
  84. package/dist/icons/index.js +2 -0
  85. package/dist/icons/index.js.map +1 -0
  86. package/dist/manageSubscriptionPage/CancelSubscriptionPage.d.ts +3 -0
  87. package/dist/manageSubscriptionPage/CancelSubscriptionPage.js +53 -0
  88. package/dist/manageSubscriptionPage/CancelSubscriptionPage.js.map +1 -0
  89. package/dist/manageSubscriptionPage/CancelSuccessPage.d.ts +3 -0
  90. package/dist/manageSubscriptionPage/CancelSuccessPage.js +24 -0
  91. package/dist/manageSubscriptionPage/CancelSuccessPage.js.map +1 -0
  92. package/dist/manageSubscriptionPage/ManageSubscriptionPage.d.ts +3 -0
  93. package/dist/manageSubscriptionPage/ManageSubscriptionPage.js +87 -0
  94. package/dist/manageSubscriptionPage/ManageSubscriptionPage.js.map +1 -0
  95. package/dist/messages.js +2 -2
  96. package/dist/messages.js.map +1 -1
  97. package/dist/routes.d.ts +9 -2
  98. package/dist/routes.js +26 -6
  99. package/dist/routes.js.map +1 -1
  100. package/dist/style.scss +1 -14
  101. package/dist/styles/components/manageSubscription.scss +454 -0
  102. package/dist/types.d.ts +61 -201
  103. package/dist/types.js +3 -0
  104. package/dist/types.js.map +1 -1
  105. package/dist/utils/billingDetails.d.ts +3 -20
  106. package/dist/utils/billingDetails.js +4 -25
  107. package/dist/utils/billingDetails.js.map +1 -1
  108. package/dist/utils/edxSession.d.ts +18 -0
  109. package/dist/utils/edxSession.js +72 -0
  110. package/dist/utils/edxSession.js.map +1 -0
  111. package/dist/utils/formatDate.d.ts +16 -0
  112. package/dist/utils/formatDate.js +69 -0
  113. package/dist/utils/formatDate.js.map +1 -0
  114. package/dist/utils/graphqlClient.d.ts +9 -10
  115. package/dist/utils/graphqlClient.js +22 -11
  116. package/dist/utils/graphqlClient.js.map +1 -1
  117. package/dist/utils/invoiceAmount.d.ts +22 -0
  118. package/dist/utils/invoiceAmount.js +59 -0
  119. package/dist/utils/invoiceAmount.js.map +1 -0
  120. package/dist/utils/queries.d.ts +38 -33
  121. package/dist/utils/queries.js +85 -123
  122. package/dist/utils/queries.js.map +1 -1
  123. package/dist/utils/subscriptionView.d.ts +15 -0
  124. package/dist/utils/subscriptionView.js +50 -0
  125. package/dist/utils/subscriptionView.js.map +1 -0
  126. package/dist/utils/urls.d.ts +20 -0
  127. package/dist/utils/urls.js +76 -0
  128. package/dist/utils/urls.js.map +1 -0
  129. package/package.json +7 -2
  130. package/dist/checkoutPage/CheckoutPage.d.ts +0 -3
  131. package/dist/checkoutPage/CheckoutPage.js +0 -30
  132. package/dist/checkoutPage/CheckoutPage.js.map +0 -1
  133. package/dist/components/BrandMarks/BrandMarks.d.ts +0 -3
  134. package/dist/components/BrandMarks/BrandMarks.js +0 -9
  135. package/dist/components/BrandMarks/BrandMarks.js.map +0 -1
  136. package/dist/components/CartSummary/CartSummary.d.ts +0 -21
  137. package/dist/components/CartSummary/CartSummary.js +0 -30
  138. package/dist/components/CartSummary/CartSummary.js.map +0 -1
  139. package/dist/components/CartSummary/Messages.d.ts +0 -73
  140. package/dist/components/CartSummary/Messages.js +0 -76
  141. package/dist/components/CartSummary/Messages.js.map +0 -1
  142. package/dist/components/Checkout/Checkout.d.ts +0 -4
  143. package/dist/components/Checkout/Checkout.js +0 -40
  144. package/dist/components/Checkout/Checkout.js.map +0 -1
  145. package/dist/components/CheckoutGate/CheckoutGate.d.ts +0 -7
  146. package/dist/components/CheckoutGate/CheckoutGate.js +0 -35
  147. package/dist/components/CheckoutGate/CheckoutGate.js.map +0 -1
  148. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.d.ts +0 -9
  149. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js +0 -31
  150. package/dist/components/CourseEnrollmentCard/CourseEnrollmentCard.js.map +0 -1
  151. package/dist/components/CourseEnrollmentCard/Messages.d.ts +0 -33
  152. package/dist/components/CourseEnrollmentCard/Messages.js +0 -35
  153. package/dist/components/CourseEnrollmentCard/Messages.js.map +0 -1
  154. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.d.ts +0 -13
  155. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js +0 -11
  156. package/dist/components/EdxUnlimitedBanner/EdxUnlimitedBanner.js.map +0 -1
  157. package/dist/components/EnrollmentSummary/EnrollmentSummary.d.ts +0 -15
  158. package/dist/components/EnrollmentSummary/EnrollmentSummary.js +0 -21
  159. package/dist/components/EnrollmentSummary/EnrollmentSummary.js.map +0 -1
  160. package/dist/components/EnrollmentSummary/Messages.d.ts +0 -33
  161. package/dist/components/EnrollmentSummary/Messages.js +0 -35
  162. package/dist/components/EnrollmentSummary/Messages.js.map +0 -1
  163. package/dist/components/PaymentFields/PaymentFields.d.ts +0 -9
  164. package/dist/components/PaymentFields/PaymentFields.js +0 -7
  165. package/dist/components/PaymentFields/PaymentFields.js.map +0 -1
  166. package/dist/components/PaymentForm/Messages.d.ts +0 -88
  167. package/dist/components/PaymentForm/Messages.js +0 -95
  168. package/dist/components/PaymentForm/Messages.js.map +0 -1
  169. package/dist/components/PaymentForm/PaymentForm.d.ts +0 -21
  170. package/dist/components/PaymentForm/PaymentForm.js +0 -69
  171. package/dist/components/PaymentForm/PaymentForm.js.map +0 -1
  172. package/dist/components/StatusScreens/Messages.d.ts +0 -103
  173. package/dist/components/StatusScreens/Messages.js +0 -108
  174. package/dist/components/StatusScreens/Messages.js.map +0 -1
  175. package/dist/components/StatusScreens/StatusScreens.d.ts +0 -23
  176. package/dist/components/StatusScreens/StatusScreens.js +0 -25
  177. package/dist/components/StatusScreens/StatusScreens.js.map +0 -1
  178. package/dist/data/hooks/useCheckout.d.ts +0 -57
  179. package/dist/data/hooks/useCheckout.js +0 -249
  180. package/dist/data/hooks/useCheckout.js.map +0 -1
  181. package/dist/data/hooks/useCheckoutGate.d.ts +0 -15
  182. package/dist/data/hooks/useCheckoutGate.js +0 -39
  183. package/dist/data/hooks/useCheckoutGate.js.map +0 -1
  184. package/dist/data/hooks/useCheckoutMutations.d.ts +0 -16
  185. package/dist/data/hooks/useCheckoutMutations.js +0 -131
  186. package/dist/data/hooks/useCheckoutMutations.js.map +0 -1
  187. package/dist/data/hooks/useCheckoutQueries.d.ts +0 -30
  188. package/dist/data/hooks/useCheckoutQueries.js +0 -97
  189. package/dist/data/hooks/useCheckoutQueries.js.map +0 -1
  190. package/dist/styles/components/brandMarks.scss +0 -54
  191. package/dist/styles/components/cartSummary.scss +0 -18
  192. package/dist/styles/components/checkout.scss +0 -29
  193. package/dist/styles/components/checkoutStepper.scss +0 -9
  194. package/dist/styles/components/courseEnrollmentCard.scss +0 -38
  195. package/dist/styles/components/edxUnlimitedBanner.scss +0 -138
  196. package/dist/styles/components/enrollmentSummary.scss +0 -13
  197. package/dist/styles/components/paymentFields.scss +0 -15
  198. package/dist/styles/components/paymentForm.scss +0 -105
  199. package/dist/styles/components/statusScreens.scss +0 -29
  200. package/dist/styles/components/successScreen.scss +0 -0
  201. package/dist/utils/auth.d.ts +0 -7
  202. package/dist/utils/auth.js +0 -28
  203. package/dist/utils/auth.js.map +0 -1
  204. package/dist/utils/bootstrapApi.d.ts +0 -20
  205. package/dist/utils/bootstrapApi.js +0 -142
  206. package/dist/utils/bootstrapApi.js.map +0 -1
  207. package/dist/utils/cartApi.d.ts +0 -16
  208. package/dist/utils/cartApi.js +0 -118
  209. package/dist/utils/cartApi.js.map +0 -1
  210. package/dist/utils/checkout.d.ts +0 -6
  211. package/dist/utils/checkout.js +0 -28
  212. package/dist/utils/checkout.js.map +0 -1
  213. package/dist/utils/fetchActiveSubscriptions.d.ts +0 -4
  214. package/dist/utils/fetchActiveSubscriptions.js +0 -36
  215. package/dist/utils/fetchActiveSubscriptions.js.map +0 -1
  216. package/dist/utils/fetchBillingPlans.d.ts +0 -2
  217. package/dist/utils/fetchBillingPlans.js.map +0 -1
  218. package/dist/utils/index.d.ts +0 -3
  219. package/dist/utils/index.js +0 -17
  220. package/dist/utils/index.js.map +0 -1
  221. package/dist/utils/provision.d.ts +0 -25
  222. package/dist/utils/provision.js +0 -95
  223. package/dist/utils/provision.js.map +0 -1
  224. package/dist/utils/stripe.d.ts +0 -7
  225. package/dist/utils/stripe.js +0 -43
  226. package/dist/utils/stripe.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -1,39 +1,72 @@
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 {
1
+ /**
2
+ * Manage Subscription — domain types for Viax subscriber + enrollment data.
3
+ */
4
+ /** GraphQL runner used by VIAX fetchers. */
5
+ export type GqlRunner = (query: string, variables?: Record<string, unknown>) => Promise<any>;
6
+ /** Result of `tIsCurrentUserSubscriber` (JSON scalar). */
7
+ export interface CurrentUserSubscriberResult {
8
+ /** Has/expects access — drive manage vs upsell messaging. */
9
+ isSubscriber: boolean;
10
+ /** Enrollable right now (ACTIVE / TRIAL_ACTIVE). */
11
+ canEnroll: boolean;
12
+ subscriptionBiId: string | null;
13
+ status: string | null;
14
+ currentPeriodEnd: string | null;
15
+ subscriptionStartDate: string | null;
16
+ subscriptionEndDate: string | null;
17
+ /**
18
+ * Billing cycle / plan label used by UI (from `billingFrequency`,
19
+ * `renewalType`, or `planName` on the API payload).
20
+ */
21
+ renewalType?: string | null;
22
+ /** Optional cancel timestamp when present. */
23
+ canceledAt?: string | null;
24
+ /** Optional price display amount when present. */
25
+ amount?: string | null;
26
+ currency?: string | null;
27
+ }
28
+ /** Normalized enrollment for the cancel confirmation course list. */
29
+ export interface SubscriptionEnrollment {
23
30
  biId: string;
24
- uid: string;
31
+ courseMaId: string | null;
32
+ courseName: string | null;
33
+ courseSlug: string | null;
34
+ /** Course card / thumbnail image. */
35
+ imageUrl: string | null;
36
+ orgName: string | null;
37
+ orgLogoUrl: string | null;
38
+ courseRunKey: string | null;
39
+ /** TwouEnrollment bpStatus.code (ACTIVE, COMPLETED, …). */
40
+ status: string | null;
41
+ /** True when the enrollment has a certificate id and/or URL. */
42
+ hasCertificate: boolean;
43
+ /** Absolute certificate link (`COURSES_BASE_URL` + `tCertificateUrl`). */
44
+ certificateUrl: string | null;
25
45
  }
26
- export interface CartIds {
27
- customerUid: string;
28
- salableUid: string;
29
- billingPlanUid: string;
46
+ /** Normalized invoice row for the Payment history tab. */
47
+ export interface PaymentHistoryItem {
48
+ biId: string;
49
+ /** Display order number, e.g. EDX-BI3X25N5SY30OSIK */
50
+ orderNumber: string;
51
+ stripeInvoiceId: string | null;
52
+ status: string | null;
53
+ billDate: string | null;
54
+ periodStart: string | null;
55
+ periodEnd: string | null;
56
+ /** Charged amount in major currency units (e.g. 59.00). */
57
+ amount: number;
58
+ currency: string;
59
+ isTrial: boolean;
30
60
  }
61
+ /** UI view derived from subscriber status. */
62
+ export type SubscriptionView = 'none' | 'active' | 'canceled_access' | 'canceled_expired';
63
+ export type ManageTab = 'subscription' | 'payment-history';
31
64
  export type BillingCycle = 'monthly' | 'annual';
32
- export type BillingPeriod = 'MONTHLY' | 'ANNUAL' | 'QUARTERLY' | string;
33
65
  export interface BillingPlanOwnershipModel {
34
66
  uid: string;
35
67
  omName: string;
36
68
  }
69
+ /** Normalized row from `filterCustomerBillingPlan`. */
37
70
  export interface BillingPlan {
38
71
  uid: string;
39
72
  stripePriceId: string;
@@ -44,179 +77,6 @@ export interface BillingPlan {
44
77
  isTemplate: boolean;
45
78
  ownershipModel: BillingPlanOwnershipModel;
46
79
  }
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
80
  export interface BillingPlansResult {
90
81
  plans: BillingPlan[];
91
82
  }
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
- }
package/dist/types.js CHANGED
@@ -1,2 +1,5 @@
1
+ /**
2
+ * Manage Subscription — domain types for Viax subscriber + enrollment data.
3
+ */
1
4
  export {};
2
5
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Status, Phase } from './constants';\n\nexport type { Status, Phase };\n\n// --- Bootstrap domain --------------------------------------------------------\nexport interface TwouCustomerContact {\n email?: string,\n}\n\nexport interface TwouCustomerParty {\n paName: string,\n indFirstName?: string,\n indLastName?: string,\n paContacts: { edges: { node: TwouCustomerContact }[] },\n}\n\nexport interface TwouCustomer {\n uid: string,\n parId: string,\n parParty: TwouCustomerParty,\n}\n\nexport type GqlRunner = (query: string, variables?: Record<string, unknown>, retry?: boolean) => Promise<any>;\n\n// --- Cart domain -------------------------------------------------------------\nexport interface Cart {\n biId: string,\n uid: string,\n}\n\nexport interface CartIds {\n customerUid: string,\n salableUid: string,\n billingPlanUid: string,\n}\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport type BillingPeriod = 'MONTHLY' | 'ANNUAL' | 'QUARTERLY' | string;\n\nexport interface BillingPlanOwnershipModel {\n uid: string,\n omName: string,\n}\n\nexport interface BillingPlan {\n uid: string,\n stripePriceId: string,\n /** Price amount e.g. \"39.99\" */\n amount: string,\n /** Currency code e.g. \"USD\" */\n currency: string,\n isTemplate: boolean,\n ownershipModel: BillingPlanOwnershipModel,\n}\n\nexport interface SubscriptionDetails {\n biId: string, // \"BI301ZDAD6CMICG2\"\n trialStart: string | null,\n trialEnd: string | null,\n renewalType: string | null, // \"Annual\" | \"Monthly\"\n cardLast4: string | null, // \"4242\"\n cardBrand: string | null, // \"visa\" | \"mastercard\" etc\n stripePaymentMethodId: string | null,\n planName: string | null, // \"Monthly Subscription\"\n}\n\nexport interface CurrentUserSubscriberResult {\n isSubscriber: boolean,\n subscriptionBiId: string | null,\n status: string | null,\n subscriptionStartDate: string | null,\n currentPeriodEnd: string | null,\n}\n\n/** Course shown on checkout / post-checkout when arriving via ?course_run_key=. */\nexport interface CourseDetail {\n maId: string,\n maName: string,\n maDescription: string | null,\n tShortDescription: string | null,\n imageUrl: string | null,\n tCourseKey: string | null,\n tBrandText: string | null,\n tPrimarySubjectArea: string | null,\n tLevelType: string | null,\n tLanguage: string | null,\n tPacingType: string | null,\n tDurationLow: number | null,\n tDurationHigh: number | null,\n tDurationUnit: string | null,\n tEffortLow: number | null,\n tEffortHigh: number | null,\n tEffortUnit: string | null,\n tUrlCourse: string | null,\n tB2cSubscriptionInclusion: boolean | null,\n tHasOfacRestrictions: boolean | null,\n tCatalogActive: boolean | null,\n}\n\n/** Returned by getBillingPlans — all available plans for the product. */\nexport interface BillingPlansResult {\n plans: BillingPlan[],\n}\n\n/** Returned by getSalableUid — the product uid and its ownership models. */\nexport interface ProductInfo {\n uid: string,\n maName: string,\n ownershipModels: { uid: string, omName: string }[],\n}\n\nexport interface CartStatusResult {\n status: Status | null,\n stripeSubscriptionId: string | null,\n lastComment: string,\n}\n\nexport interface CartBillingAddress {\n tFirstName: string,\n tLastName: string,\n upaLine1: string,\n upaCity: string,\n upaPostcode: string,\n gadStateOrProvince: string,\n gadCountry: { iso2Code: string },\n}\n\nexport interface UpdateCartItemArgs {\n cartItemUid: string,\n billingAddress?: CartBillingAddress,\n paymentMethodId?: string,\n}\n\n/** Auto-renewal consent captured on TwouCart at checkout confirmation (SUBS-228). */\nexport interface CheckoutConsent {\n /** Main auto-renewal checkbox — always required at submit. */\n tConsentRecurring: boolean,\n /** UK/CA resident checkbox; null when that checkbox is not shown. */\n tConsentUkCa: boolean | null,\n /** ISO-8601 timestamp when consent was captured. */\n tConsentAt: string,\n /** Exact disclosure text shown to the learner (audit trail). */\n tConsentText: string,\n}\n\nexport interface UpdateCartConsentArgs {\n cartUid: string,\n consent: CheckoutConsent,\n}\n\nexport interface BillingInfo {\n firstName: string,\n lastName: string,\n city: string,\n zip: string,\n country: string,\n line1: string,\n state: string,\n}\n\n// --- Checkout client surface -------------------------------------------------\nexport interface CheckoutClient {\n gql: GqlRunner,\n setToken: (token: string) => void,\n createCart: (vars: CartIds) => Promise<Cart>,\n getCartItem: (biId: string) => Promise<{ cartUid: string, cartItemUid: string }>,\n updateCartItem: (args: UpdateCartItemArgs) => Promise<void>,\n updateCartConsent: (args: UpdateCartConsentArgs) => Promise<void>,\n placeOrder: (cartUid: string) => Promise<unknown>,\n getCartStatus: (biId: string) => Promise<CartStatusResult>,\n findSubscriptionBiId: (biId: string) => Promise<SubscriptionDetails | null>,\n getSalableUid: (maId: string) => Promise<ProductInfo>,\n getBillingPlans: () => Promise<BillingPlansResult>,\n getActiveSubscriptions: () => Promise<{ active: number }>,\n isCurrentUserSubscriber: () => Promise<CurrentUserSubscriberResult | null>,\n getCourseDetail: (courseKey: string) => Promise<CourseDetail | null>,\n}\n\nexport interface DevAuth {\n iamUrl: string,\n clientId: string,\n clientSecret: string,\n}\n\n// --- Minimal Stripe.js types -------------------------------------------------\n// Just the surface this module uses. If you depend on `@stripe/stripe-js`,\n// you can replace these with its richer types.\nexport interface StripeElementChangeEvent {\n error?: { message?: string },\n [key: string]: unknown,\n}\n\nexport interface StripeElementLike {\n mount: (node: HTMLElement) => void,\n on: (event: string, handler: (e: StripeElementChangeEvent) => void) => void,\n unmount?: () => void,\n}\n\nexport interface StripeElementsLike {\n create: (type: string, options?: Record<string, unknown>) => StripeElementLike,\n}\n\nexport interface StripeError {\n message?: string,\n code?: string,\n}\n\nexport interface PaymentMethodResult {\n paymentMethod?: { id: string },\n error?: StripeError,\n}\n\nexport interface ConfirmResult {\n error?: StripeError,\n setupIntent?: unknown,\n paymentIntent?: unknown,\n}\n\nexport interface CreatePaymentMethodParams {\n type: 'card',\n card: StripeElementLike,\n billing_details?: Record<string, unknown>,\n}\n\nexport interface StripeLike {\n elements: () => StripeElementsLike,\n createPaymentMethod: (params: CreatePaymentMethodParams) => Promise<PaymentMethodResult>,\n confirmCardSetup: (clientSecret: string) => Promise<ConfirmResult>,\n confirmCardPayment: (clientSecret: string) => Promise<ConfirmResult>,\n}\n\ndeclare global {\n interface Window {\n Stripe?: (publishableKey: string) => StripeLike,\n }\n}\n\nexport interface TrialDateRange {\n /** e.g. \"June 22, 2026\" */\n displayStart: string,\n /** e.g. \"June 29, 2026\" */\n displayEnd: string,\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * Manage Subscription — domain types for Viax subscriber + enrollment data.\n */\n\n/** GraphQL runner used by VIAX fetchers. */\nexport type GqlRunner = (\n query: string,\n variables?: Record<string, unknown>,\n) => Promise<any>;\n\n/** Result of `tIsCurrentUserSubscriber` (JSON scalar). */\nexport interface CurrentUserSubscriberResult {\n /** Has/expects access — drive manage vs upsell messaging. */\n isSubscriber: boolean,\n /** Enrollable right now (ACTIVE / TRIAL_ACTIVE). */\n canEnroll: boolean,\n subscriptionBiId: string | null,\n status: string | null,\n currentPeriodEnd: string | null,\n subscriptionStartDate: string | null,\n subscriptionEndDate: string | null,\n /**\n * Billing cycle / plan label used by UI (from `billingFrequency`,\n * `renewalType`, or `planName` on the API payload).\n */\n renewalType?: string | null,\n /** Optional cancel timestamp when present. */\n canceledAt?: string | null,\n /** Optional price display amount when present. */\n amount?: string | null,\n currency?: string | null,\n}\n\n/** Normalized enrollment for the cancel confirmation course list. */\nexport interface SubscriptionEnrollment {\n biId: string,\n courseMaId: string | null,\n courseName: string | null,\n courseSlug: string | null,\n /** Course card / thumbnail image. */\n imageUrl: string | null,\n orgName: string | null,\n orgLogoUrl: string | null,\n courseRunKey: string | null,\n /** TwouEnrollment bpStatus.code (ACTIVE, COMPLETED, …). */\n status: string | null,\n /** True when the enrollment has a certificate id and/or URL. */\n hasCertificate: boolean,\n /** Absolute certificate link (`COURSES_BASE_URL` + `tCertificateUrl`). */\n certificateUrl: string | null,\n}\n\n/** Normalized invoice row for the Payment history tab. */\nexport interface PaymentHistoryItem {\n biId: string,\n /** Display order number, e.g. EDX-BI3X25N5SY30OSIK */\n orderNumber: string,\n stripeInvoiceId: string | null,\n status: string | null,\n billDate: string | null,\n periodStart: string | null,\n periodEnd: string | null,\n /** Charged amount in major currency units (e.g. 59.00). */\n amount: number,\n currency: string,\n isTrial: boolean,\n}\n\n/** UI view derived from subscriber status. */\nexport type SubscriptionView =\n | 'none'\n | 'active'\n | 'canceled_access'\n | 'canceled_expired';\n\nexport type ManageTab = 'subscription' | 'payment-history';\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport interface BillingPlanOwnershipModel {\n uid: string,\n omName: string,\n}\n\n/** Normalized row from `filterCustomerBillingPlan`. */\nexport interface BillingPlan {\n uid: string,\n stripePriceId: string,\n /** Price amount e.g. \"39.99\" */\n amount: string,\n /** Currency code e.g. \"USD\" */\n currency: string,\n isTemplate: boolean,\n ownershipModel: BillingPlanOwnershipModel,\n}\n\nexport interface BillingPlansResult {\n plans: BillingPlan[],\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { BillingPlan, BillingCycle } from '../types';
1
+ import type { BillingCycle, BillingPlan } from '../types';
2
2
  export interface PlanPrice {
3
3
  uid: string;
4
4
  stripePriceId: string;
@@ -7,24 +7,7 @@ export interface PlanPrice {
7
7
  label: string;
8
8
  }
9
9
  /**
10
- * getPlanPrice — returns the price for the selected billing cycle.
11
- *
12
- * Matches plans by looking for "annual"/"year" or "month" in omName.
13
- * Falls back to the first plan if no match is found.
14
- *
15
- * @example
16
- * getPlanPrice(billingPlans, 'monthly')
17
- * // → { uid: '...', amount: '11', currency: 'USD', label: '$11 USD/month' }
18
- *
19
- * getPlanPrice(billingPlans, 'annual')
20
- * // → { uid: '...', amount: '111', currency: 'USD', label: '$111 USD/year' }
10
+ * Returns the price for the selected billing cycle.
11
+ * Matches plans by "annual"/"year" or "month" in omName; falls back to first plan.
21
12
  */
22
13
  export declare function getPlanPrice(plans: BillingPlan[], cycle: BillingCycle): PlanPrice | null;
23
- /**
24
- * getRenewalLabel — returns a "Then $X/month" style label for CartSummary.
25
- *
26
- * @example
27
- * getRenewalLabel(billingPlans, 'monthly') // → "Then $11 USD/month"
28
- * getRenewalLabel(billingPlans, 'annual') // → "Then $111 USD/year"
29
- */
30
- export declare function getRenewalLabel(plans: BillingPlan[], cycle: BillingCycle): string;
@@ -1,20 +1,12 @@
1
1
  /**
2
- * getPlanPrice — returns the price for the selected billing cycle.
3
- *
4
- * Matches plans by looking for "annual"/"year" or "month" in omName.
5
- * Falls back to the first plan if no match is found.
6
- *
7
- * @example
8
- * getPlanPrice(billingPlans, 'monthly')
9
- * // → { uid: '...', amount: '11', currency: 'USD', label: '$11 USD/month' }
10
- *
11
- * getPlanPrice(billingPlans, 'annual')
12
- * // → { uid: '...', amount: '111', currency: 'USD', label: '$111 USD/year' }
2
+ * Returns the price for the selected billing cycle.
3
+ * Matches plans by "annual"/"year" or "month" in omName; falls back to first plan.
13
4
  */
14
5
  export function getPlanPrice(plans, cycle) {
15
6
  var _a;
16
- if (!plans.length)
7
+ if (!plans.length) {
17
8
  return null;
9
+ }
18
10
  const isAnnual = cycle === 'annual';
19
11
  const match = (_a = plans.find((p) => {
20
12
  var _a, _b;
@@ -31,17 +23,4 @@ export function getPlanPrice(plans, cycle) {
31
23
  label: `$${match.amount} ${match.currency}/${isAnnual ? 'year' : 'month'}`,
32
24
  };
33
25
  }
34
- /**
35
- * getRenewalLabel — returns a "Then $X/month" style label for CartSummary.
36
- *
37
- * @example
38
- * getRenewalLabel(billingPlans, 'monthly') // → "Then $11 USD/month"
39
- * getRenewalLabel(billingPlans, 'annual') // → "Then $111 USD/year"
40
- */
41
- export function getRenewalLabel(plans, cycle) {
42
- const price = getPlanPrice(plans, cycle);
43
- if (!price)
44
- return '';
45
- return `Then $${price.amount} ${price.currency}/${cycle === 'annual' ? 'year' : 'month'}`;
46
- }
47
26
  //# sourceMappingURL=billingDetails.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"billingDetails.js","sourceRoot":"","sources":["../../src/utils/billingDetails.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAoB,EACpB,KAAmB;;IAEnB,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,QAAQ,GAAG,KAAK,KAAK,QAAQ,CAAC;IAEpC,MAAM,KAAK,GAAG,MAAA,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;;QAC7B,MAAM,IAAI,GAAG,MAAA,MAAA,CAAC,CAAC,cAAc,CAAC,MAAM,0CAAE,WAAW,EAAE,mCAAI,EAAE,CAAC;QAC1D,OAAO,QAAQ;YACb,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAClD,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,mCAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IAEf,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;KAC3E,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAoB,EACpB,KAAmB;IAEnB,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,SAAS,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAC5F,CAAC","sourcesContent":["import type { BillingPlan, BillingCycle } from '../types';\n\nexport interface PlanPrice {\n uid: string,\n stripePriceId: string,\n amount: string,\n currency: string,\n label: string, // e.g. \"$11 USD/month\"\n}\n\n/**\n * getPlanPrice — returns the price for the selected billing cycle.\n *\n * Matches plans by looking for \"annual\"/\"year\" or \"month\" in omName.\n * Falls back to the first plan if no match is found.\n *\n * @example\n * getPlanPrice(billingPlans, 'monthly')\n * // → { uid: '...', amount: '11', currency: 'USD', label: '$11 USD/month' }\n *\n * getPlanPrice(billingPlans, 'annual')\n * // → { uid: '...', amount: '111', currency: 'USD', label: '$111 USD/year' }\n */\nexport function getPlanPrice(\n plans: BillingPlan[],\n cycle: BillingCycle,\n): PlanPrice | null {\n if (!plans.length) return null;\n\n const isAnnual = cycle === 'annual';\n\n const match = plans.find((p) => {\n const name = p.ownershipModel.omName?.toLowerCase() ?? '';\n return isAnnual\n ? name.includes('annual') || name.includes('year')\n : name.includes('month');\n }) ?? plans[0];\n\n return {\n uid: match.uid,\n stripePriceId: match.stripePriceId,\n amount: match.amount,\n currency: match.currency,\n label: `$${match.amount} ${match.currency}/${isAnnual ? 'year' : 'month'}`,\n };\n}\n\n/**\n * getRenewalLabel — returns a \"Then $X/month\" style label for CartSummary.\n *\n * @example\n * getRenewalLabel(billingPlans, 'monthly') // → \"Then $11 USD/month\"\n * getRenewalLabel(billingPlans, 'annual') // → \"Then $111 USD/year\"\n */\nexport function getRenewalLabel(\n plans: BillingPlan[],\n cycle: BillingCycle,\n): string {\n const price = getPlanPrice(plans, cycle);\n if (!price) return '';\n return `Then $${price.amount} ${price.currency}/${cycle === 'annual' ? 'year' : 'month'}`;\n}\n"]}
1
+ {"version":3,"file":"billingDetails.js","sourceRoot":"","sources":["../../src/utils/billingDetails.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAoB,EACpB,KAAmB;;IAEnB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,KAAK,QAAQ,CAAC;IAEpC,MAAM,KAAK,GAAG,MAAA,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;;QAC7B,MAAM,IAAI,GAAG,MAAA,MAAA,CAAC,CAAC,cAAc,CAAC,MAAM,0CAAE,WAAW,EAAE,mCAAI,EAAE,CAAC;QAC1D,OAAO,QAAQ;YACb,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAClD,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,mCAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IAEf,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;KAC3E,CAAC;AACJ,CAAC","sourcesContent":["import type { BillingCycle, BillingPlan } from '../types';\n\nexport interface PlanPrice {\n uid: string,\n stripePriceId: string,\n amount: string,\n currency: string,\n label: string,\n}\n\n/**\n * Returns the price for the selected billing cycle.\n * Matches plans by \"annual\"/\"year\" or \"month\" in omName; falls back to first plan.\n */\nexport function getPlanPrice(\n plans: BillingPlan[],\n cycle: BillingCycle,\n): PlanPrice | null {\n if (!plans.length) {\n return null;\n }\n\n const isAnnual = cycle === 'annual';\n\n const match = plans.find((p) => {\n const name = p.ownershipModel.omName?.toLowerCase() ?? '';\n return isAnnual\n ? name.includes('annual') || name.includes('year')\n : name.includes('month');\n }) ?? plans[0];\n\n return {\n uid: match.uid,\n stripePriceId: match.stripePriceId,\n amount: match.amount,\n currency: match.currency,\n label: `$${match.amount} ${match.currency}/${isAnnual ? 'year' : 'month'}`,\n };\n}\n"]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Exchange the learner's edX session for a Viax JWT.
3
+ *
4
+ * Dev uses POST with a hardcoded JWT payload (local LMS cookie exchange is
5
+ * unavailable). Stage/prod use POST with browser session cookies.
6
+ */
7
+ export interface EdxSessionResult {
8
+ viaxToken: string;
9
+ customerUid: string;
10
+ partyUid?: string;
11
+ edxUserId?: string;
12
+ username?: string;
13
+ email?: string;
14
+ }
15
+ /** LMS edx-session endpoint for the current site. */
16
+ export declare function getEdxSessionUrl(): string;
17
+ /** Exchange the learner's edX session for a Viax token. */
18
+ export declare function fetchEdxSession(sessionUrl: string): Promise<EdxSessionResult>;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Exchange the learner's edX session for a Viax JWT.
3
+ *
4
+ * Dev uses POST with a hardcoded JWT payload (local LMS cookie exchange is
5
+ * unavailable). Stage/prod use POST with browser session cookies.
6
+ */
7
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
14
+ });
15
+ };
16
+ import { EnvironmentTypes, getSiteConfig } from '@openedx/frontend-base';
17
+ /** Hardcoded edX JWT used only for local/dev against Viax (same pattern as enroll/checkout MFEs). */
18
+ const DEV_SESSION_BODY = {
19
+ payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.eyJhdWQiOiJJbmtvY3VqTGlreXVjc0Vkd2lXYXRkZWJyRWFja21ldkxha0R1aWZLb29zaGtha1dvdyIsImV4cCI6MTc4NzY3MDk3MCwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwiaWF0IjoxNzg3NjY3MzcwLCJpc3MiOiJodHRwczovL2NvdXJzZXMuc3RhZ2UuZWR4Lm9yZy9vYXV0aDIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJNXzI2MDhfT1o2QSIsInNjb3BlcyI6WyJ1c2VyX2lkIiwiZW1haWwiLCJwcm9maWxlIl0sInZlcnNpb24iOiIxLjIuMCIsInN1YiI6ImU4MGRhNjk4MjQ1MWM2MmVmZmM3MDc0MjRjOTVmNjVlIiwiZmlsdGVycyI6WyJ1c2VyOm1lIl0sImlzX3Jlc3RyaWN0ZWQiOmZhbHNlLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwidXNlcl9pZCI6NTI4NDk1NywiZW1haWwiOiJtc2FoYS1zb25hdGErVGVzdHVzZXIwMUAydS5jb20iLCJuYW1lIjoiTWFoYS1CMkMtVGVzdCIsImZhbWlseV9uYW1lIjoiIiwiZ2l2ZW5fbmFtZSI6IiIsImFkbWluaXN0cmF0b3IiOmZhbHNlLCJzdXBlcnVzZXIiOmZhbHNlfQ',
20
+ signature: 'DjXh1h8I8U8hRQmgEDn58gWQcxM7wBmDj0jJpWVb_Li5JvnVr-3a8MAsmtxa8MIEitYVJIXvq-AAenGYbJBbPYYpeYZ7DT-WERf341F4mokhsRSSXKIaLp6Gk-341879jC9UkXz-DeXEpoAJDaY4879wR3daaaOTmtS5jxj6ywOhlVYM4D4gGluXFdKAQ3sANJfUIA5YA_QKJWM434SUo6YGifQ-ZyVreDK7OdGOygkyVti4T4UusEtaJ0Zh_yXbZEc6gbmPOuE7ndzlTh25LZx_vwXpcx_QI_YlBKO0aMoL5J2ma9_O0jqqgN9-hhCbU09_GTw2lpM2tf6GmK4b7A'
21
+ };
22
+ function parseSessionResponse(data) {
23
+ var _a, _b, _c, _d;
24
+ const viaxToken = ((_c = (_b = (_a = data.viaxToken) !== null && _a !== void 0 ? _a : data.token) !== null && _b !== void 0 ? _b : data.access_token) !== null && _c !== void 0 ? _c : data.accessToken);
25
+ const customerUid = ((_d = data.customerUid) !== null && _d !== void 0 ? _d : data.customer_uid);
26
+ if (!viaxToken) {
27
+ throw new Error('Session response missing viax token.');
28
+ }
29
+ if (!customerUid) {
30
+ throw new Error('Session response missing customerUid.');
31
+ }
32
+ return {
33
+ viaxToken,
34
+ customerUid,
35
+ partyUid: data.partyUid,
36
+ edxUserId: data.edxUserId,
37
+ username: data.username,
38
+ email: data.email,
39
+ };
40
+ }
41
+ function isDevelopment() {
42
+ return getSiteConfig().environment === EnvironmentTypes.DEVELOPMENT;
43
+ }
44
+ /** LMS edx-session endpoint for the current site. */
45
+ export function getEdxSessionUrl() {
46
+ return isDevelopment()
47
+ ? 'https://courses.stage.edx.org/api/edx-session'
48
+ : `${getSiteConfig().lmsBaseUrl}/api/edx-session`;
49
+ }
50
+ /** Exchange the learner's edX session for a Viax token. */
51
+ export function fetchEdxSession(sessionUrl) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ const res = yield fetch(sessionUrl, {
54
+ method: 'POST',
55
+ credentials: 'include',
56
+ headers: {
57
+ Accept: 'application/json',
58
+ 'Content-Type': 'application/json',
59
+ },
60
+ body: isDevelopment() ? JSON.stringify(DEV_SESSION_BODY) : undefined,
61
+ });
62
+ if (!res.ok) {
63
+ throw new Error(`Failed to establish session (${res.status}). Please log into edX and try again.`);
64
+ }
65
+ const data = yield res.json();
66
+ if (data.error) {
67
+ throw new Error(String(data.error));
68
+ }
69
+ return parseSessionResponse(data);
70
+ });
71
+ }
72
+ //# sourceMappingURL=edxSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edxSession.js","sourceRoot":"","sources":["../../src/utils/edxSession.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;;;;;;;;;;AAEH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAWzE,qGAAqG;AACrG,MAAM,gBAAgB,GAAG;IACvB,OAAO,EAAE,ovBAAovB;IAC7vB,SAAS,EAAE,wVAAwV;CACpW,CAAC;AAEF,SAAS,oBAAoB,CAAC,IAA6B;;IACzD,MAAM,SAAS,GAAG,CAChB,MAAA,MAAA,MAAA,IAAI,CAAC,SAAS,mCAAI,IAAI,CAAC,KAAK,mCAAI,IAAI,CAAC,YAAY,mCAAI,IAAI,CAAC,WAAW,CAChD,CAAC;IACxB,MAAM,WAAW,GAAG,CAAC,MAAA,IAAI,CAAC,WAAW,mCAAI,IAAI,CAAC,YAAY,CAAuB,CAAC;IAElF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,SAAS;QACT,WAAW;QACX,QAAQ,EAAE,IAAI,CAAC,QAA8B;QAC7C,SAAS,EAAE,IAAI,CAAC,SAA+B;QAC/C,QAAQ,EAAE,IAAI,CAAC,QAA8B;QAC7C,KAAK,EAAE,IAAI,CAAC,KAA2B;KACxC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,aAAa,EAAE,CAAC,WAAW,KAAK,gBAAgB,CAAC,WAAW,CAAC;AACtE,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,aAAa,EAAE;QACpB,CAAC,CAAC,+CAA+C;QACjD,CAAC,CAAC,GAAG,aAAa,EAAE,CAAC,UAAU,kBAAkB,CAAC;AACtD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAgB,eAAe,CAAC,UAAkB;;QACtD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,SAAS;YACtB,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS;SACrE,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,gCAAgC,GAAG,CAAC,MAAM,uCAAuC,CAClF,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAkD,CAAC;QAC9E,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CAAA","sourcesContent":["/**\n * Exchange the learner's edX session for a Viax JWT.\n *\n * Dev uses POST with a hardcoded JWT payload (local LMS cookie exchange is\n * unavailable). Stage/prod use POST with browser session cookies.\n */\n\nimport { EnvironmentTypes, getSiteConfig } from '@openedx/frontend-base';\n\nexport interface EdxSessionResult {\n viaxToken: string,\n customerUid: string,\n partyUid?: string,\n edxUserId?: string,\n username?: string,\n email?: string,\n}\n\n/** Hardcoded edX JWT used only for local/dev against Viax (same pattern as enroll/checkout MFEs). */\nconst DEV_SESSION_BODY = {\n payload: 'eyJhbGciOiJSUzUxMiIsImtpZCI6Imxtc3N0YWdlMDAyIiwidHlwIjoiSldUIn0.eyJhdWQiOiJJbmtvY3VqTGlreXVjc0Vkd2lXYXRkZWJyRWFja21ldkxha0R1aWZLb29zaGtha1dvdyIsImV4cCI6MTc4NzY3MDk3MCwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwiaWF0IjoxNzg3NjY3MzcwLCJpc3MiOiJodHRwczovL2NvdXJzZXMuc3RhZ2UuZWR4Lm9yZy9vYXV0aDIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJNXzI2MDhfT1o2QSIsInNjb3BlcyI6WyJ1c2VyX2lkIiwiZW1haWwiLCJwcm9maWxlIl0sInZlcnNpb24iOiIxLjIuMCIsInN1YiI6ImU4MGRhNjk4MjQ1MWM2MmVmZmM3MDc0MjRjOTVmNjVlIiwiZmlsdGVycyI6WyJ1c2VyOm1lIl0sImlzX3Jlc3RyaWN0ZWQiOmZhbHNlLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwidXNlcl9pZCI6NTI4NDk1NywiZW1haWwiOiJtc2FoYS1zb25hdGErVGVzdHVzZXIwMUAydS5jb20iLCJuYW1lIjoiTWFoYS1CMkMtVGVzdCIsImZhbWlseV9uYW1lIjoiIiwiZ2l2ZW5fbmFtZSI6IiIsImFkbWluaXN0cmF0b3IiOmZhbHNlLCJzdXBlcnVzZXIiOmZhbHNlfQ',\n signature: 'DjXh1h8I8U8hRQmgEDn58gWQcxM7wBmDj0jJpWVb_Li5JvnVr-3a8MAsmtxa8MIEitYVJIXvq-AAenGYbJBbPYYpeYZ7DT-WERf341F4mokhsRSSXKIaLp6Gk-341879jC9UkXz-DeXEpoAJDaY4879wR3daaaOTmtS5jxj6ywOhlVYM4D4gGluXFdKAQ3sANJfUIA5YA_QKJWM434SUo6YGifQ-ZyVreDK7OdGOygkyVti4T4UusEtaJ0Zh_yXbZEc6gbmPOuE7ndzlTh25LZx_vwXpcx_QI_YlBKO0aMoL5J2ma9_O0jqqgN9-hhCbU09_GTw2lpM2tf6GmK4b7A'\n};\n\nfunction parseSessionResponse(data: Record<string, unknown>): EdxSessionResult {\n const viaxToken = (\n data.viaxToken ?? data.token ?? data.access_token ?? data.accessToken\n ) as string | undefined;\n const customerUid = (data.customerUid ?? data.customer_uid) as string | undefined;\n\n if (!viaxToken) {\n throw new Error('Session response missing viax token.');\n }\n if (!customerUid) {\n throw new Error('Session response missing customerUid.');\n }\n\n return {\n viaxToken,\n customerUid,\n partyUid: data.partyUid as string | undefined,\n edxUserId: data.edxUserId as string | undefined,\n username: data.username as string | undefined,\n email: data.email as string | undefined,\n };\n}\n\nfunction isDevelopment(): boolean {\n return getSiteConfig().environment === EnvironmentTypes.DEVELOPMENT;\n}\n\n/** LMS edx-session endpoint for the current site. */\nexport function getEdxSessionUrl(): string {\n return isDevelopment()\n ? 'https://courses.stage.edx.org/api/edx-session'\n : `${getSiteConfig().lmsBaseUrl}/api/edx-session`;\n}\n\n/** Exchange the learner's edX session for a Viax token. */\nexport async function fetchEdxSession(sessionUrl: string): Promise<EdxSessionResult> {\n const res = await fetch(sessionUrl, {\n method: 'POST',\n credentials: 'include',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: isDevelopment() ? JSON.stringify(DEV_SESSION_BODY) : undefined,\n });\n\n if (!res.ok) {\n throw new Error(\n `Failed to establish session (${res.status}). Please log into edX and try again.`,\n );\n }\n\n const data = await res.json() as Record<string, unknown> & { error?: string };\n if (data.error) {\n throw new Error(String(data.error));\n }\n\n return parseSessionResponse(data);\n}\n"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Format ISO date strings for manage-subscription copy.
3
+ */
4
+ /**
5
+ * Formats a date for display, e.g. "April 13, 2027".
6
+ * Uses the calendar date from YYYY-MM-DD to avoid timezone day-shift.
7
+ * Returns null when the value cannot be parsed.
8
+ */
9
+ export declare function formatDisplayDate(value: string | null | undefined, locale?: string): string | null;
10
+ /**
11
+ * Formats a date as MM/DD/YYYY (en-US), e.g. "10/13/2026".
12
+ * Returns null when the value cannot be parsed.
13
+ */
14
+ export declare function formatNumericDate(value: string | null | undefined, locale?: string): string | null;
15
+ /** True when the ISO date is strictly in the future. */
16
+ export declare function isFutureDate(value: string | null | undefined): boolean;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Format ISO date strings for manage-subscription copy.
3
+ */
4
+ function parseDate(value) {
5
+ const dateOnly = /^(\d{4})-(\d{2})-(\d{2})/.exec(value);
6
+ let date;
7
+ if (dateOnly) {
8
+ const year = Number(dateOnly[1]);
9
+ const month = Number(dateOnly[2]) - 1;
10
+ const day = Number(dateOnly[3]);
11
+ date = new Date(year, month, day);
12
+ }
13
+ else {
14
+ date = new Date(value);
15
+ }
16
+ if (Number.isNaN(date.getTime())) {
17
+ return null;
18
+ }
19
+ return date;
20
+ }
21
+ /**
22
+ * Formats a date for display, e.g. "April 13, 2027".
23
+ * Uses the calendar date from YYYY-MM-DD to avoid timezone day-shift.
24
+ * Returns null when the value cannot be parsed.
25
+ */
26
+ export function formatDisplayDate(value, locale = 'en-US') {
27
+ if (!value) {
28
+ return null;
29
+ }
30
+ const date = parseDate(value);
31
+ if (!date) {
32
+ return null;
33
+ }
34
+ return new Intl.DateTimeFormat(locale, {
35
+ month: 'long',
36
+ day: 'numeric',
37
+ year: 'numeric',
38
+ }).format(date);
39
+ }
40
+ /**
41
+ * Formats a date as MM/DD/YYYY (en-US), e.g. "10/13/2026".
42
+ * Returns null when the value cannot be parsed.
43
+ */
44
+ export function formatNumericDate(value, locale = 'en-US') {
45
+ if (!value) {
46
+ return null;
47
+ }
48
+ const date = parseDate(value);
49
+ if (!date) {
50
+ return null;
51
+ }
52
+ return new Intl.DateTimeFormat(locale, {
53
+ month: '2-digit',
54
+ day: '2-digit',
55
+ year: 'numeric',
56
+ }).format(date);
57
+ }
58
+ /** True when the ISO date is strictly in the future. */
59
+ export function isFutureDate(value) {
60
+ if (!value) {
61
+ return false;
62
+ }
63
+ const date = new Date(value);
64
+ if (Number.isNaN(date.getTime())) {
65
+ return false;
66
+ }
67
+ return date.getTime() > Date.now();
68
+ }
69
+ //# sourceMappingURL=formatDate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatDate.js","sourceRoot":"","sources":["../../src/utils/formatDate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,QAAQ,GAAG,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,IAAI,IAAU,CAAC;IACf,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAgC,EAChC,MAAM,GAAG,OAAO;IAEhB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QACrC,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;KAChB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAgC,EAChC,MAAM,GAAG,OAAO;IAEhB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QACrC,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;KAChB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,KAAgC;IAC3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AACrC,CAAC","sourcesContent":["/**\n * Format ISO date strings for manage-subscription copy.\n */\n\nfunction parseDate(value: string): Date | null {\n const dateOnly = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value);\n let date: Date;\n if (dateOnly) {\n const year = Number(dateOnly[1]);\n const month = Number(dateOnly[2]) - 1;\n const day = Number(dateOnly[3]);\n date = new Date(year, month, day);\n } else {\n date = new Date(value);\n }\n\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n return date;\n}\n\n/**\n * Formats a date for display, e.g. \"April 13, 2027\".\n * Uses the calendar date from YYYY-MM-DD to avoid timezone day-shift.\n * Returns null when the value cannot be parsed.\n */\nexport function formatDisplayDate(\n value: string | null | undefined,\n locale = 'en-US',\n): string | null {\n if (!value) {\n return null;\n }\n\n const date = parseDate(value);\n if (!date) {\n return null;\n }\n\n return new Intl.DateTimeFormat(locale, {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n }).format(date);\n}\n\n/**\n * Formats a date as MM/DD/YYYY (en-US), e.g. \"10/13/2026\".\n * Returns null when the value cannot be parsed.\n */\nexport function formatNumericDate(\n value: string | null | undefined,\n locale = 'en-US',\n): string | null {\n if (!value) {\n return null;\n }\n\n const date = parseDate(value);\n if (!date) {\n return null;\n }\n\n return new Intl.DateTimeFormat(locale, {\n month: '2-digit',\n day: '2-digit',\n year: 'numeric',\n }).format(date);\n}\n\n/** True when the ISO date is strictly in the future. */\nexport function isFutureDate(value: string | null | undefined): boolean {\n if (!value) {\n return false;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return false;\n }\n return date.getTime() > Date.now();\n}\n"]}
@@ -1,16 +1,15 @@
1
1
  /**
2
- * api/graphqlClient.ts — authed GraphQL client.
2
+ * Minimal GraphQL client for VIAX.
3
3
  *
4
- * No token is required at construction. Call setToken(viaxToken) after
5
- * GET /edx-session returns — typically on checkout page mount.
6
- *
7
- * On 401 the token is cleared and the request fails — the mutation will
8
- * surface the error and the user can retry.
4
+ * Authenticated calls (subscriber check, enrollments, cancel) require setToken()
5
+ * after exchanging the edX session for a Viax JWT.
9
6
  */
10
7
  import type { GqlRunner } from '../types';
8
+ export interface ViaxGqlClient {
9
+ gql: GqlRunner;
10
+ setToken: (token: string | null) => void;
11
+ hasToken: () => boolean;
12
+ }
11
13
  export declare function createGqlClient({ apiUrl }: {
12
14
  apiUrl: string;
13
- }): {
14
- gql: GqlRunner;
15
- setToken: (token: string) => void;
16
- };
15
+ }): ViaxGqlClient;