@edx/frontend-app-subscription-checkout 1.22.4 → 1.24.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.
|
@@ -11,6 +11,7 @@ export interface CommonTrackingProps {
|
|
|
11
11
|
current_period_end?: string | null;
|
|
12
12
|
user_email?: string | null;
|
|
13
13
|
payment_method?: string | null;
|
|
14
|
+
opt_in?: boolean | null;
|
|
14
15
|
}
|
|
15
16
|
export declare const setCommonTrackingProps: (props: CommonTrackingProps) => void;
|
|
16
17
|
export declare const getCommonTrackingProps: () => CommonTrackingProps;
|
|
@@ -6,7 +6,7 @@ export const setCommonTrackingProps = (props) => {
|
|
|
6
6
|
export const getCommonTrackingProps = () => commonProps;
|
|
7
7
|
// Single place that maps the subs/init API response -> tracking props
|
|
8
8
|
export const mapSubsInitToTrackingProps = (data) => {
|
|
9
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
10
10
|
return ({
|
|
11
11
|
free_trial_status: (_a = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _a === void 0 ? void 0 : _a.trialActive,
|
|
12
12
|
subscription_status: (_b = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _b === void 0 ? void 0 : _b.status,
|
|
@@ -20,6 +20,7 @@ export const mapSubsInitToTrackingProps = (data) => {
|
|
|
20
20
|
current_period_end: (_g = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _g === void 0 ? void 0 : _g.currentPeriodEnd,
|
|
21
21
|
user_email: (_h = getAuthenticatedUser()) === null || _h === void 0 ? void 0 : _h.email,
|
|
22
22
|
payment_method: (_j = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _j === void 0 ? void 0 : _j.paymentMethod,
|
|
23
|
+
opt_in: (_k = data === null || data === void 0 ? void 0 : data.opt_in) !== null && _k !== void 0 ? _k : null,
|
|
23
24
|
// TODO: add marketing opt-in status field from the API response that should be tracked
|
|
24
25
|
});
|
|
25
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trackingContext.js","sourceRoot":"","sources":["../../src/tracking/trackingContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"trackingContext.js","sourceRoot":"","sources":["../../src/tracking/trackingContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAiB9D,IAAI,WAAW,GAAwB,EAAE,CAAC;AAE1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAA0B,EAAE,EAAE;IACnE,WAAW,mCAAQ,WAAW,GAAK,KAAK,CAAE,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAwB,EAAE,CAAC,WAAW,CAAC;AAE7E,sEAAsE;AACtE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,IAAS,EAAuB,EAAE;;IAAC,OAAA,CAAC;QAC7E,iBAAiB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,WAAW;QACtD,mBAAmB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,MAAM;QACnD,iBAAiB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,gBAAgB;QAC3D,UAAU,EAAE,EAAE;QACd,eAAe,EAAE,EAAE;QACnB,WAAW,EAAE,EAAE;QACf,uBAAuB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,SAAS;QAC1D,qBAAqB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,OAAO;QACtD,2BAA2B,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,YAAY;QACjE,kBAAkB,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,gBAAgB;QAC5D,UAAU,EAAE,MAAA,oBAAoB,EAAE,0CAAE,KAAK;QACzC,cAAc,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,aAAa;QACrD,MAAM,EAAE,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,mCAAI,IAAI;QAC5B,uFAAuF;KACxF,CAAC,CAAA;CAAA,CAAC","sourcesContent":["import { getAuthenticatedUser } from '@openedx/frontend-base';\nexport interface CommonTrackingProps {\n free_trial_status?: string,\n subscription_status?: string,\n subscription_tier?: string,\n session_id?: string | null,\n experimentation?: string | null,\n device_type?: string | null,\n subscription_start_date?: string | null,\n subscription_end_date?: string | null,\n subscription_trial_end_date?: string | null,\n current_period_end?: string | null,\n user_email?: string | null,\n payment_method?: string | null,\n opt_in?: boolean | null,\n}\n\nlet commonProps: CommonTrackingProps = {};\n\nexport const setCommonTrackingProps = (props: CommonTrackingProps) => {\n commonProps = { ...commonProps, ...props };\n};\n\nexport const getCommonTrackingProps = (): CommonTrackingProps => commonProps;\n\n// Single place that maps the subs/init API response -> tracking props\nexport const mapSubsInitToTrackingProps = (data: any): CommonTrackingProps => ({\n free_trial_status: data?.userSubscription?.trialActive,\n subscription_status: data?.userSubscription?.status,\n subscription_tier: data?.userSubscription?.billingFrequency,\n session_id: '',\n experimentation: '',\n device_type: '',\n subscription_start_date: data?.userSubscription?.startDate,\n subscription_end_date: data?.userSubscription?.endDate,\n subscription_trial_end_date: data?.userSubscription?.trialEndDate,\n current_period_end: data?.userSubscription?.currentPeriodEnd,\n user_email: getAuthenticatedUser()?.email,\n payment_method: data?.userSubscription?.paymentMethod,\n opt_in: data?.opt_in ?? null,\n // TODO: add marketing opt-in status field from the API response that should be tracked\n});\n"]}
|
|
@@ -15,6 +15,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
* billingPlanUid — selected from filterCustomerBillingPlan by the caller.
|
|
16
16
|
*/
|
|
17
17
|
import { GET_CUSTOMER, GET_BILLING_PLANS, GET_PRODUCT, GET_ACTIVE_SUBSCRIPTIONS_STATE, GET_IS_CURRENT_USER_SUBSCRIBER, GET_COURSE_DETAIL } from './queries';
|
|
18
|
+
import { getSiteConfig } from '@openedx/frontend-base';
|
|
18
19
|
/** Resolve the viax customer uid for the authenticated user by email. */
|
|
19
20
|
export function getCustomerUid(gql, userEmail) {
|
|
20
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -104,38 +105,62 @@ export function getActiveSubscriptions(gql) {
|
|
|
104
105
|
* Sends the course key to Viax exactly as provided (e.g. HarvardX+CS50+X). */
|
|
105
106
|
export function getCourseDetail(gql, courseKey) {
|
|
106
107
|
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
|
|
108
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3;
|
|
108
109
|
const key = courseKey.trim();
|
|
109
110
|
if (!key)
|
|
110
111
|
return null;
|
|
112
|
+
const siteConfig = getSiteConfig();
|
|
113
|
+
const LMS_BASE_URL = siteConfig.lmsBaseUrl;
|
|
114
|
+
// 1. Fetch resolved key from Partner REST API
|
|
115
|
+
let resolvedCourseKey = key;
|
|
116
|
+
try {
|
|
117
|
+
const url = new URL(`${LMS_BASE_URL.replace(/\/$/, '')}/api/subscription/course-runs`);
|
|
118
|
+
url.searchParams.set('key', key);
|
|
119
|
+
const res = yield fetch(url.toString(), {
|
|
120
|
+
method: 'GET',
|
|
121
|
+
headers: { Accept: 'application/json' },
|
|
122
|
+
});
|
|
123
|
+
if (res.ok) {
|
|
124
|
+
const payload = yield res.json();
|
|
125
|
+
// Extract key from elements array as per Partner API response format
|
|
126
|
+
const partnerApiKey = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.elements) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.key;
|
|
127
|
+
if (partnerApiKey) {
|
|
128
|
+
resolvedCourseKey = partnerApiKey;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// If Partner API fails, fallback gracefully to the original key
|
|
134
|
+
console.error('Failed to fetch course run key from Partner API:', error);
|
|
135
|
+
}
|
|
111
136
|
// Escape single quotes for the filter string only — do not alter `+` or other chars.
|
|
112
|
-
const filter = `tCourseKey = '${
|
|
137
|
+
const filter = `tCourseKey = '${resolvedCourseKey.replace(/'/g, "''")}'`;
|
|
113
138
|
const data = yield gql(GET_COURSE_DETAIL, { filter });
|
|
114
|
-
const node = (
|
|
139
|
+
const node = (_e = (_d = (_c = data === null || data === void 0 ? void 0 : data.filterTwouCourse) === null || _c === void 0 ? void 0 : _c.edges) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.node;
|
|
115
140
|
if (!(node === null || node === void 0 ? void 0 : node.maId))
|
|
116
141
|
return null;
|
|
117
142
|
return {
|
|
118
143
|
maId: node.maId,
|
|
119
|
-
maName: (
|
|
120
|
-
maDescription: (
|
|
121
|
-
tShortDescription: (
|
|
122
|
-
imageUrl: (
|
|
123
|
-
tCourseKey: (
|
|
124
|
-
tBrandText: (
|
|
125
|
-
tPrimarySubjectArea: (
|
|
126
|
-
tLevelType: (
|
|
127
|
-
tLanguage: (
|
|
128
|
-
tPacingType: (
|
|
129
|
-
tDurationLow: (
|
|
130
|
-
tDurationHigh: (
|
|
131
|
-
tDurationUnit: (
|
|
132
|
-
tEffortLow: (
|
|
133
|
-
tEffortHigh: (
|
|
134
|
-
tEffortUnit: (
|
|
135
|
-
tUrlCourse: (
|
|
136
|
-
tB2cSubscriptionInclusion: (
|
|
137
|
-
tHasOfacRestrictions: (
|
|
138
|
-
tCatalogActive: (
|
|
144
|
+
maName: (_f = node.maName) !== null && _f !== void 0 ? _f : '',
|
|
145
|
+
maDescription: (_g = node.maDescription) !== null && _g !== void 0 ? _g : null,
|
|
146
|
+
tShortDescription: (_h = node.tShortDescription) !== null && _h !== void 0 ? _h : null,
|
|
147
|
+
imageUrl: (_j = node.imageUrl) !== null && _j !== void 0 ? _j : null,
|
|
148
|
+
tCourseKey: (_k = node.tCourseKey) !== null && _k !== void 0 ? _k : null,
|
|
149
|
+
tBrandText: (_l = node.tBrandText) !== null && _l !== void 0 ? _l : null,
|
|
150
|
+
tPrimarySubjectArea: (_m = node.tPrimarySubjectArea) !== null && _m !== void 0 ? _m : null,
|
|
151
|
+
tLevelType: (_o = node.tLevelType) !== null && _o !== void 0 ? _o : null,
|
|
152
|
+
tLanguage: (_p = node.tLanguage) !== null && _p !== void 0 ? _p : null,
|
|
153
|
+
tPacingType: (_r = (_q = node.tPacingType) === null || _q === void 0 ? void 0 : _q.code) !== null && _r !== void 0 ? _r : null,
|
|
154
|
+
tDurationLow: (_s = node.tDurationLow) !== null && _s !== void 0 ? _s : null,
|
|
155
|
+
tDurationHigh: (_t = node.tDurationHigh) !== null && _t !== void 0 ? _t : null,
|
|
156
|
+
tDurationUnit: (_v = (_u = node.tDurationUnit) === null || _u === void 0 ? void 0 : _u.code) !== null && _v !== void 0 ? _v : null,
|
|
157
|
+
tEffortLow: (_w = node.tEffortLow) !== null && _w !== void 0 ? _w : null,
|
|
158
|
+
tEffortHigh: (_x = node.tEffortHigh) !== null && _x !== void 0 ? _x : null,
|
|
159
|
+
tEffortUnit: (_z = (_y = node.tEffortUnit) === null || _y === void 0 ? void 0 : _y.code) !== null && _z !== void 0 ? _z : null,
|
|
160
|
+
tUrlCourse: (_0 = node.tUrlCourse) !== null && _0 !== void 0 ? _0 : null,
|
|
161
|
+
tB2cSubscriptionInclusion: (_1 = node.tB2cSubscriptionInclusion) !== null && _1 !== void 0 ? _1 : null,
|
|
162
|
+
tHasOfacRestrictions: (_2 = node.tHasOfacRestrictions) !== null && _2 !== void 0 ? _2 : null,
|
|
163
|
+
tCatalogActive: (_3 = node.tCatalogActive) !== null && _3 !== void 0 ? _3 : null,
|
|
139
164
|
};
|
|
140
165
|
});
|
|
141
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapApi.js","sourceRoot":"","sources":["../../src/utils/bootstrapApi.ts"],"names":[],"mappings":";;;;;;;;;AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,8BAA8B,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG5J,yEAAyE;AACzE,MAAM,UAAgB,cAAc,CAAC,GAAc,EAAE,SAAiB;;;QACpE,MAAM,MAAM,GAAG,gCAAgC,SAAS,GAAG,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD,MAAM,IAAI,GAA6B,MAAA,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,kBAAkB,0CAAE,KAAK,0CAAG,CAAC,CAAC,0CAAE,IAAI,CAAC;QAClF,IAAI,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,GAAG,CAAA;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,SAAS,kCAAkC,CAAC,CAAC;QAC3G,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;CAAA;AAED;;;;GAIG;AACH,MAAM,UAAgB,aAAa,CAAC,GAAc,EAAE,IAAY;;;QAC9D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,CAAC;QACjC,IAAI,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAA;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,cAAc,CAAC,CAAC;QACnE,OAAO;YACL,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,MAAA,OAAO,CAAC,MAAM,mCAAI,EAAE;YAC5B,eAAe,EAAE,CAAC,MAAA,OAAO,CAAC,iBAAiB,mCAAI,EAAE,CAAC,CAAC,GAAG,CACpD,CAAC,CAAkC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAC3E;SACF,CAAC;IACJ,CAAC;CAAA;AAED,kDAAkD;AAClD,MAAM,UAAgB,eAAe,CAAC,GAAc;;;QAClD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAC1C,MAAM,KAAK,GAQL,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,yBAAyB,0CAAE,KAAK,mCAAI,EAAE,CAAC;QAEnD,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAE9D,MAAM,KAAK,GAAkB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;;YAAC,OAAA,CAAC;gBACpD,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,aAAa,EAAE,IAAI,CAAC,cAAc;gBAClC,MAAM,EAAE,MAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,MAAM,mCAAI,GAAG;gBACzC,QAAQ,EAAE,MAAA,MAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,KAAK,0CAAE,IAAI,mCAAI,KAAK;gBAClD,UAAU,EAAE,IAAI,CAAC,aAAa;gBAC9B,cAAc,EAAE;oBACd,GAAG,EAAE,MAAA,MAAA,IAAI,CAAC,iBAAiB,0CAAE,GAAG,mCAAI,EAAE;oBACtC,MAAM,EAAE,MAAA,MAAA,IAAI,CAAC,iBAAiB,0CAAE,MAAM,mCAAI,EAAE;iBAC7C;aACF,CAAC,CAAA;SAAA,CAAC,CAAC;QAEJ,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;CAAA;AAED,yFAAyF;AACzF,MAAM,UAAgB,uBAAuB,CAAC,GAAc;;;QAC1D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,wBAAwB,CAAC;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO;YACL,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,IAAI;YAC1C,gBAAgB,EAAE,MAAA,MAAM,CAAC,gBAAgB,mCAAI,IAAI;YACjD,MAAM,EAAE,MAAA,MAAM,CAAC,MAAM,mCAAI,IAAI;YAC7B,qBAAqB,EAAE,MAAA,MAAM,CAAC,qBAAqB,mCAAI,IAAI;YAC3D,gBAAgB,EAAE,MAAA,MAAM,CAAC,gBAAgB,mCAAI,IAAI;SAClD,CAAC;IACJ,CAAC;CAAA;AAED,gDAAgD;AAChD,MAAM,UAAgB,sBAAsB,CAAC,GAAc;;;QACzD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,8BAA8B,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,yBAAyB,0CAAE,MAAM,CAAC;QACvD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC;CAAA;AAED;+EAC+E;AAC/E,MAAM,UAAgB,eAAe,CAAC,GAAc,EAAE,SAAiB;;;QACrE,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,qFAAqF;QACrF,MAAM,MAAM,GAAG,iBAAiB,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;QAC3D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAA,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,0CAAE,KAAK,0CAAG,CAAC,CAAC,0CAAE,IAAI,CAAC;QACtD,IAAI,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI,CAAA;YAAE,OAAO,IAAI,CAAC;QAE7B,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,MAAA,IAAI,CAAC,MAAM,mCAAI,EAAE;YACzB,aAAa,EAAE,MAAA,IAAI,CAAC,aAAa,mCAAI,IAAI;YACzC,iBAAiB,EAAE,MAAA,IAAI,CAAC,iBAAiB,mCAAI,IAAI;YACjD,QAAQ,EAAE,MAAA,IAAI,CAAC,QAAQ,mCAAI,IAAI;YAC/B,UAAU,EAAE,MAAA,IAAI,CAAC,UAAU,mCAAI,IAAI;YACnC,UAAU,EAAE,MAAA,IAAI,CAAC,UAAU,mCAAI,IAAI;YACnC,mBAAmB,EAAE,MAAA,IAAI,CAAC,mBAAmB,mCAAI,IAAI;YACrD,UAAU,EAAE,MAAA,IAAI,CAAC,UAAU,mCAAI,IAAI;YACnC,SAAS,EAAE,MAAA,IAAI,CAAC,SAAS,mCAAI,IAAI;YACjC,WAAW,EAAE,MAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,mCAAI,IAAI;YAC3C,YAAY,EAAE,MAAA,IAAI,CAAC,YAAY,mCAAI,IAAI;YACvC,aAAa,EAAE,MAAA,IAAI,CAAC,aAAa,mCAAI,IAAI;YACzC,aAAa,EAAE,MAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,IAAI,mCAAI,IAAI;YAC/C,UAAU,EAAE,MAAA,IAAI,CAAC,UAAU,mCAAI,IAAI;YACnC,WAAW,EAAE,MAAA,IAAI,CAAC,WAAW,mCAAI,IAAI;YACrC,WAAW,EAAE,MAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,mCAAI,IAAI;YAC3C,UAAU,EAAE,MAAA,IAAI,CAAC,UAAU,mCAAI,IAAI;YACnC,yBAAyB,EAAE,MAAA,IAAI,CAAC,yBAAyB,mCAAI,IAAI;YACjE,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,IAAI;YACvD,cAAc,EAAE,MAAA,IAAI,CAAC,cAAc,mCAAI,IAAI;SAC5C,CAAC;IACJ,CAAC;CAAA","sourcesContent":["/**\n * api/bootstrapApi.ts — fetch the runtime ids needed to create a cart.\n *\n * customerUid — looked up by the user's email from their viax party record.\n * salableUid — the product uid from getProduct(maId), used as biiSalable.\n * billingPlanUid — selected from filterCustomerBillingPlan by the caller.\n */\nimport { GET_CUSTOMER, GET_BILLING_PLANS, GET_PRODUCT, GET_ACTIVE_SUBSCRIPTIONS_STATE, GET_IS_CURRENT_USER_SUBSCRIBER, GET_COURSE_DETAIL } from './queries';\nimport type { GqlRunner, BillingPlansResult, BillingPlan, TwouCustomer, ProductInfo, CurrentUserSubscriberResult, CourseDetail } from '../types';\n\n/** Resolve the viax customer uid for the authenticated user by email. */\nexport async function getCustomerUid(gql: GqlRunner, userEmail: string): Promise<string> {\n const filter = `parParty.paContacts.email = '${userEmail}'`;\n const data = await gql(GET_CUSTOMER, { filter });\n const node: TwouCustomer | undefined = data?.filterTwouCustomer?.edges?.[0]?.node;\n if (!node?.uid) throw new Error(`No viax customer found for ${userEmail}. Ensure your account is linked.`);\n return node.uid;\n}\n\n/**\n * Fetch the TwouSubscriptionPlan uid to use as biiSalable in createTwouCart.\n * The maId is the product market-area identifier, e.g. \"TWOU-SUB-PLAN-001\".\n * The returned `uid` is passed as biiSalable when creating the cart.\n */\nexport async function getSalableUid(gql: GqlRunner, maId: string): Promise<ProductInfo> {\n const data = await gql(GET_PRODUCT, { maId });\n const product = data?.getProduct;\n if (!product?.uid) throw new Error(`Product \"${maId}\" not found.`);\n return {\n uid: product.uid,\n maName: product.maName ?? '',\n ownershipModels: (product.saOwnershipModels ?? []).map(\n (m: { uid: string, omName: string }) => ({ uid: m.uid, omName: m.omName }),\n ),\n };\n}\n\n/** Fetch all available customer billing plans. */\nexport async function getBillingPlans(gql: GqlRunner): Promise<BillingPlansResult> {\n const data = await gql(GET_BILLING_PLANS);\n const edges: {\n node: {\n uid: string,\n tStripePriceId: string,\n tStripeAmount?: { amount: string, units?: { code: string } },\n bipIsTemplate: boolean,\n bipOwnershipModel?: { uid: string, omName: string },\n },\n }[] = data?.filterCustomerBillingPlan?.edges ?? [];\n\n if (!edges.length) throw new Error('No billing plans found.');\n\n const plans: BillingPlan[] = edges.map(({ node }) => ({\n uid: node.uid,\n stripePriceId: node.tStripePriceId,\n amount: node.tStripeAmount?.amount ?? '0',\n currency: node.tStripeAmount?.units?.code ?? 'USD',\n isTemplate: node.bipIsTemplate,\n ownershipModel: {\n uid: node.bipOwnershipModel?.uid ?? '',\n omName: node.bipOwnershipModel?.omName ?? '',\n },\n }));\n\n return { plans };\n}\n\n/** Check whether the currently authenticated user already has an active subscription. */\nexport async function isCurrentUserSubscriber(gql: GqlRunner): Promise<CurrentUserSubscriberResult | null> {\n const data = await gql(GET_IS_CURRENT_USER_SUBSCRIBER);\n const result = data?.tIsCurrentUserSubscriber;\n if (!result) return null;\n return {\n isSubscriber: result.isSubscriber === true,\n subscriptionBiId: result.subscriptionBiId ?? null,\n status: result.status ?? null,\n subscriptionStartDate: result.subscriptionStartDate ?? null,\n currentPeriodEnd: result.currentPeriodEnd ?? null,\n };\n}\n\n/** Fetch the number of active subscriptions. */\nexport async function getActiveSubscriptions(gql: GqlRunner): Promise<{ active: number }> {\n const data = await gql(GET_ACTIVE_SUBSCRIPTIONS_STATE);\n const active = data?.tActiveSubscriptionsState?.active;\n if (typeof active !== 'number') {\n throw new Error('Unexpected response shape for tActiveSubscriptionsState');\n }\n return { active };\n}\n\n/** Fetch course details for the enrollment card by tCourseKey.\n * Sends the course key to Viax exactly as provided (e.g. HarvardX+CS50+X). */\nexport async function getCourseDetail(gql: GqlRunner, courseKey: string): Promise<CourseDetail | null> {\n const key = courseKey.trim();\n if (!key) return null;\n\n // Escape single quotes for the filter string only — do not alter `+` or other chars.\n const filter = `tCourseKey = '${key.replace(/'/g, \"''\")}'`;\n const data = await gql(GET_COURSE_DETAIL, { filter });\n const node = data?.filterTwouCourse?.edges?.[0]?.node;\n if (!node?.maId) return null;\n\n return {\n maId: node.maId,\n maName: node.maName ?? '',\n maDescription: node.maDescription ?? null,\n tShortDescription: node.tShortDescription ?? null,\n imageUrl: node.imageUrl ?? null,\n tCourseKey: node.tCourseKey ?? null,\n tBrandText: node.tBrandText ?? null,\n tPrimarySubjectArea: node.tPrimarySubjectArea ?? null,\n tLevelType: node.tLevelType ?? null,\n tLanguage: node.tLanguage ?? null,\n tPacingType: node.tPacingType?.code ?? null,\n tDurationLow: node.tDurationLow ?? null,\n tDurationHigh: node.tDurationHigh ?? null,\n tDurationUnit: node.tDurationUnit?.code ?? null,\n tEffortLow: node.tEffortLow ?? null,\n tEffortHigh: node.tEffortHigh ?? null,\n tEffortUnit: node.tEffortUnit?.code ?? null,\n tUrlCourse: node.tUrlCourse ?? null,\n tB2cSubscriptionInclusion: node.tB2cSubscriptionInclusion ?? null,\n tHasOfacRestrictions: node.tHasOfacRestrictions ?? null,\n tCatalogActive: node.tCatalogActive ?? null,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bootstrapApi.js","sourceRoot":"","sources":["../../src/utils/bootstrapApi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/bootstrapApi.ts — fetch the runtime ids needed to create a cart.\n *\n * customerUid — looked up by the user's email from their viax party record.\n * salableUid — the product uid from getProduct(maId), used as biiSalable.\n * billingPlanUid — selected from filterCustomerBillingPlan by the caller.\n */\nimport { GET_CUSTOMER, GET_BILLING_PLANS, GET_PRODUCT, GET_ACTIVE_SUBSCRIPTIONS_STATE, GET_IS_CURRENT_USER_SUBSCRIBER, GET_COURSE_DETAIL } from './queries';\nimport type { GqlRunner, BillingPlansResult, BillingPlan, TwouCustomer, ProductInfo, CurrentUserSubscriberResult, CourseDetail } from '../types';\nimport { getSiteConfig } from '@openedx/frontend-base';\n\n/** Resolve the viax customer uid for the authenticated user by email. */\nexport async function getCustomerUid(gql: GqlRunner, userEmail: string): Promise<string> {\n const filter = `parParty.paContacts.email = '${userEmail}'`;\n const data = await gql(GET_CUSTOMER, { filter });\n const node: TwouCustomer | undefined = data?.filterTwouCustomer?.edges?.[0]?.node;\n if (!node?.uid) throw new Error(`No viax customer found for ${userEmail}. Ensure your account is linked.`);\n return node.uid;\n}\n\n/**\n * Fetch the TwouSubscriptionPlan uid to use as biiSalable in createTwouCart.\n * The maId is the product market-area identifier, e.g. \"TWOU-SUB-PLAN-001\".\n * The returned `uid` is passed as biiSalable when creating the cart.\n */\nexport async function getSalableUid(gql: GqlRunner, maId: string): Promise<ProductInfo> {\n const data = await gql(GET_PRODUCT, { maId });\n const product = data?.getProduct;\n if (!product?.uid) throw new Error(`Product \"${maId}\" not found.`);\n return {\n uid: product.uid,\n maName: product.maName ?? '',\n ownershipModels: (product.saOwnershipModels ?? []).map(\n (m: { uid: string, omName: string }) => ({ uid: m.uid, omName: m.omName }),\n ),\n };\n}\n\n/** Fetch all available customer billing plans. */\nexport async function getBillingPlans(gql: GqlRunner): Promise<BillingPlansResult> {\n const data = await gql(GET_BILLING_PLANS);\n const edges: {\n node: {\n uid: string,\n tStripePriceId: string,\n tStripeAmount?: { amount: string, units?: { code: string } },\n bipIsTemplate: boolean,\n bipOwnershipModel?: { uid: string, omName: string },\n },\n }[] = data?.filterCustomerBillingPlan?.edges ?? [];\n\n if (!edges.length) throw new Error('No billing plans found.');\n\n const plans: BillingPlan[] = edges.map(({ node }) => ({\n uid: node.uid,\n stripePriceId: node.tStripePriceId,\n amount: node.tStripeAmount?.amount ?? '0',\n currency: node.tStripeAmount?.units?.code ?? 'USD',\n isTemplate: node.bipIsTemplate,\n ownershipModel: {\n uid: node.bipOwnershipModel?.uid ?? '',\n omName: node.bipOwnershipModel?.omName ?? '',\n },\n }));\n\n return { plans };\n}\n\n/** Check whether the currently authenticated user already has an active subscription. */\nexport async function isCurrentUserSubscriber(gql: GqlRunner): Promise<CurrentUserSubscriberResult | null> {\n const data = await gql(GET_IS_CURRENT_USER_SUBSCRIBER);\n const result = data?.tIsCurrentUserSubscriber;\n if (!result) return null;\n return {\n isSubscriber: result.isSubscriber === true,\n subscriptionBiId: result.subscriptionBiId ?? null,\n status: result.status ?? null,\n subscriptionStartDate: result.subscriptionStartDate ?? null,\n currentPeriodEnd: result.currentPeriodEnd ?? null,\n };\n}\n\n/** Fetch the number of active subscriptions. */\nexport async function getActiveSubscriptions(gql: GqlRunner): Promise<{ active: number }> {\n const data = await gql(GET_ACTIVE_SUBSCRIPTIONS_STATE);\n const active = data?.tActiveSubscriptionsState?.active;\n if (typeof active !== 'number') {\n throw new Error('Unexpected response shape for tActiveSubscriptionsState');\n }\n return { active };\n}\n\n/** Fetch course details for the enrollment card by tCourseKey.\n * Sends the course key to Viax exactly as provided (e.g. HarvardX+CS50+X). */\nexport async function getCourseDetail(gql: GqlRunner, courseKey: string): Promise<CourseDetail | null> {\n const key = courseKey.trim();\n if (!key) return null;\n\n const siteConfig = getSiteConfig();\n const LMS_BASE_URL = siteConfig.lmsBaseUrl;\n\n // 1. Fetch resolved key from Partner REST API\n let resolvedCourseKey = key;\n try {\n const url = new URL(`${LMS_BASE_URL.replace(/\\/$/, '')}/api/subscription/course-runs`);\n url.searchParams.set('key', key);\n\n const res = await fetch(url.toString(), {\n method: 'GET',\n headers: { Accept: 'application/json' },\n });\n\n if (res.ok) {\n const payload = await res.json();\n // Extract key from elements array as per Partner API response format\n const partnerApiKey = payload?.elements?.[0]?.key;\n if (partnerApiKey) {\n resolvedCourseKey = partnerApiKey;\n }\n }\n } catch (error) {\n // If Partner API fails, fallback gracefully to the original key\n console.error('Failed to fetch course run key from Partner API:', error);\n }\n\n // Escape single quotes for the filter string only — do not alter `+` or other chars.\n const filter = `tCourseKey = '${resolvedCourseKey.replace(/'/g, \"''\")}'`;\n const data = await gql(GET_COURSE_DETAIL, { filter });\n const node = data?.filterTwouCourse?.edges?.[0]?.node;\n if (!node?.maId) return null;\n\n return {\n maId: node.maId,\n maName: node.maName ?? '',\n maDescription: node.maDescription ?? null,\n tShortDescription: node.tShortDescription ?? null,\n imageUrl: node.imageUrl ?? null,\n tCourseKey: node.tCourseKey ?? null,\n tBrandText: node.tBrandText ?? null,\n tPrimarySubjectArea: node.tPrimarySubjectArea ?? null,\n tLevelType: node.tLevelType ?? null,\n tLanguage: node.tLanguage ?? null,\n tPacingType: node.tPacingType?.code ?? null,\n tDurationLow: node.tDurationLow ?? null,\n tDurationHigh: node.tDurationHigh ?? null,\n tDurationUnit: node.tDurationUnit?.code ?? null,\n tEffortLow: node.tEffortLow ?? null,\n tEffortHigh: node.tEffortHigh ?? null,\n tEffortUnit: node.tEffortUnit?.code ?? null,\n tUrlCourse: node.tUrlCourse ?? null,\n tB2cSubscriptionInclusion: node.tB2cSubscriptionInclusion ?? null,\n tHasOfacRestrictions: node.tHasOfacRestrictions ?? null,\n tCatalogActive: node.tCatalogActive ?? null,\n };\n}\n"]}
|