@edx/frontend-app-subscription-checkout 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/hooks/useCheckoutMutations.js +3 -1
- package/dist/data/hooks/useCheckoutMutations.js.map +1 -1
- package/dist/tracking/trackingContext.d.ts +6 -0
- package/dist/tracking/trackingContext.js +9 -1
- package/dist/tracking/trackingContext.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/auth.js +1 -0
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/cartApi.d.ts +7 -0
- package/dist/utils/cartApi.js +18 -1
- package/dist/utils/cartApi.js.map +1 -1
- package/dist/utils/checkout.js +1 -0
- package/dist/utils/checkout.js.map +1 -1
- package/dist/utils/queries.d.ts +2 -0
- package/dist/utils/queries.js +6 -0
- package/dist/utils/queries.js.map +1 -1
- package/package.json +1 -1
|
@@ -147,7 +147,9 @@ export function useCheckoutMutations(ctx) {
|
|
|
147
147
|
consent,
|
|
148
148
|
returnUrl: buildStripeReturnUrl(createdCart.biId),
|
|
149
149
|
});
|
|
150
|
-
// ── Step 5:
|
|
150
|
+
// ── Step 5: Wait for the asynchronously-created workflow ──────────────
|
|
151
|
+
yield client.waitForCartBusinessProcess(createdCart.biId);
|
|
152
|
+
// ── Step 6: Fire the backend workflow ─────────────────────────────────
|
|
151
153
|
yield client.placeOrder(createdCart.uid);
|
|
152
154
|
return createdCart;
|
|
153
155
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCheckoutMutations.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckoutMutations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * query/useCheckoutMutations.ts — write-side TanStack mutations.\n *\n * The placeOrder mutation drives the checkout sequence on button click.\n * The viax token and customerUid are established on page load via\n * GET /edx-session and passed in through sessionRef.\n *\n * Card:\n * 1. getSalableUid + getBillingPlans (parallel)\n * 2. createTwouCart\n * 3. stripe.createPaymentMethod → pm_xxx\n * 4. updateTwouCartItem → billing address + pm_xxx\n * 5. updateTwouCart → consent fields (SUBS-228)\n * 6. startBusinessProcessableTransitionV2('Sanction_Check')\n *\n * PayPal (mirrors the card sequence, skipping card tokenization):\n * 1. getSalableUid + getBillingPlans (parallel)\n * 2. createTwouCart\n * 3. updateTwouCartItem → billing address + TwouPaypalPayment\n * 4. updateTwouCart → consent fields + return URL (SUBS-228)\n * 5. startBusinessProcessableTransitionV2('Sanction_Check')\n * The backend then drives bpStatus to STRIPE_CONFIRMATION_REQUIRED and\n * populates tPaypalApprovalUrl, which useCheckout redirects to as the\n * hosted confirmation step for PayPal.\n */\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport type { RefObject } from 'react';\nimport { STATUS } from '../../constants';\nimport { checkoutKeys } from './keys';\nimport type { EdxSessionResult } from '../../utils/provision';\nimport { getPlanPrice } from '../../utils/billingDetails';\nimport { buildStripeReturnUrl } from '../../utils/stripe';\nimport type {\n CheckoutClient, StripeLike, StripeElementLike, Cart, BillingInfo,\n CartBillingAddress, CartStatusResult, CheckoutConsent, BillingCycle, SupportedPaymentMethod,\n} from '../../types';\n\nclass CardValidationError extends Error {}\n\nfunction toCartAddress(b: BillingInfo): CartBillingAddress {\n return {\n tFirstName: b.firstName,\n tLastName: b.lastName,\n upaLine1: b.line1,\n upaCity: b.city,\n upaPostcode: b.zip,\n gadStateOrProvince: b.state,\n gadCountry: { iso2Code: b.country },\n };\n}\n\nfunction toStripeAddress(b: BillingInfo): Record<string, string | undefined> {\n return {\n line1: b.line1 || undefined,\n city: b.city || undefined,\n state: b.state || undefined,\n postal_code: b.zip || undefined,\n country: b.country || undefined,\n };\n}\n\nexport interface CheckoutMutationsCtx {\n client: CheckoutClient | null,\n sessionRef: RefObject<EdxSessionResult | null>,\n stripeRef: RefObject<StripeLike | null>,\n cardNumberElRef: RefObject<StripeElementLike | null>,\n billingRef: RefObject<BillingInfo | null>,\n /** Selected monthly/annual cycle at Place order time. */\n selectedCycleRef: RefObject<BillingCycle>,\n setError: (msg: string) => void,\n setCardError: (msg: string) => void,\n onCartCreated: (cart: Cart) => void,\n}\n\nexport interface PlaceOrderArgs {\n consent: CheckoutConsent,\n paymentMethod: SupportedPaymentMethod,\n}\n\nexport function useCheckoutMutations(ctx: CheckoutMutationsCtx) {\n const queryClient = useQueryClient();\n\n const optimisticConfirm = (cartBiId: string) => {\n queryClient.setQueryData<CartStatusResult>(checkoutKeys.status(cartBiId), (old) => {\n console.log('old optimisticConfirm', old);\n return {\n status: STATUS.CONFIRM,\n stripeSubscriptionId: old?.stripeSubscriptionId ?? null,\n stripeConfirmationRedirectUrl: old?.stripeConfirmationRedirectUrl ?? null,\n paypalApprovalUrl: old?.paypalApprovalUrl ?? null,\n lastComment: old?.lastComment ?? '',\n };\n });\n queryClient.invalidateQueries({ queryKey: checkoutKeys.status(cartBiId) });\n };\n\n const placeOrder = useMutation<Cart, Error, PlaceOrderArgs>({\n mutationFn: async ({ consent, paymentMethod }) => {\n const { client, billingRef } = ctx;\n if (!client) throw new Error('Checkout is not ready yet.');\n\n // Google Pay is not currently supported.\n // if (paymentMethod === 'googlepay') {\n // throw new Error('Google Pay is not supported yet. Please choose Card or PayPal.');\n // }\n\n const billing = billingRef.current;\n if (!billing) throw new Error('Billing information is not available. Please refresh and try again.');\n\n const session = ctx.sessionRef.current;\n if (!session) {\n throw new Error('Checkout session is not ready yet. Please wait a moment and try again.');\n }\n const { customerUid } = session;\n\n // ── Step 1: Fetch salable(product) uid + billing plans in parallel ─────────────\n const [productInfo, plansResult] = await Promise.all([\n client.getSalableUid('TWOU-SUB-PLAN-001'),\n client.getBillingPlans(),\n ]);\n const salableUid = productInfo.uid;\n const selectedCycle = ctx.selectedCycleRef.current ?? 'monthly';\n const selectedPlan = getPlanPrice(plansResult.plans, selectedCycle);\n if (!selectedPlan) {\n throw new Error(`No billing plan found for ${selectedCycle} billing.`);\n }\n const billingPlanUid = selectedPlan.uid;\n\n // ── Step 2: Create the cart ───────────────────────────────────────────\n const createdCart = await client.createCart({ customerUid, salableUid, billingPlanUid });\n ctx.onCartCreated(createdCart);\n\n // ── Step 3: Attach billing address + payment method to cart item ──────\n const { cartItemUid } = await client.getCartItem(createdCart.biId);\n\n if (paymentMethod === 'paypal') {\n // No card tokenization — PayPal issues a hosted approval redirect instead.\n await client.updateCartItem({\n cartItemUid,\n billingAddress: toCartAddress(billing),\n paypalEmail: session.email ?? null,\n });\n } else {\n const stripe = ctx.stripeRef.current;\n const card = ctx.cardNumberElRef.current;\n if (!stripe || !card) throw new Error('Checkout is not ready yet.');\n\n // Tokenize the card (browser → Stripe).\n const { paymentMethod: stripePaymentMethod, error } = await stripe.createPaymentMethod({\n type: 'card',\n card,\n billing_details: {\n name: `${billing.firstName} ${billing.lastName}`.trim(),\n address: toStripeAddress(billing),\n },\n });\n if (error || !stripePaymentMethod) {\n throw new CardValidationError(error?.message || 'There was a problem with your card.');\n }\n\n await client.updateCartItem({\n cartItemUid,\n billingAddress: toCartAddress(billing),\n paymentMethodId: stripePaymentMethod.id,\n });\n }\n\n // ── Step 4: Persist consent + hosted-payment return URL on the TwouCart BI ────\n await client.updateCartConsent({\n cartUid: createdCart.uid,\n consent,\n returnUrl: buildStripeReturnUrl(createdCart.biId),\n });\n\n // ── Step 5: Fire the backend workflow ─────────────────────────────────\n await client.placeOrder(createdCart.uid);\n\n return createdCart;\n },\n onSuccess: (cart) => {\n optimisticConfirm(cart.biId);\n },\n onError: (err) => {\n if (err instanceof CardValidationError) ctx.setCardError(err.message);\n else ctx.setError(err.message);\n },\n });\n\n return { placeOrder };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"useCheckoutMutations.js","sourceRoot":"","sources":["../../../src/data/hooks/useCheckoutMutations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * query/useCheckoutMutations.ts — write-side TanStack mutations.\n *\n * The placeOrder mutation drives the checkout sequence on button click.\n * The viax token and customerUid are established on page load via\n * GET /edx-session and passed in through sessionRef.\n *\n * Card:\n * 1. getSalableUid + getBillingPlans (parallel)\n * 2. createTwouCart\n * 3. stripe.createPaymentMethod → pm_xxx\n * 4. updateTwouCartItem → billing address + pm_xxx\n * 5. updateTwouCart → consent fields (SUBS-228)\n * 6. startBusinessProcessableTransitionV2('Sanction_Check')\n *\n * PayPal (mirrors the card sequence, skipping card tokenization):\n * 1. getSalableUid + getBillingPlans (parallel)\n * 2. createTwouCart\n * 3. updateTwouCartItem → billing address + TwouPaypalPayment\n * 4. updateTwouCart → consent fields + return URL (SUBS-228)\n * 5. startBusinessProcessableTransitionV2('Sanction_Check')\n * The backend then drives bpStatus to STRIPE_CONFIRMATION_REQUIRED and\n * populates tPaypalApprovalUrl, which useCheckout redirects to as the\n * hosted confirmation step for PayPal.\n */\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport type { RefObject } from 'react';\nimport { STATUS } from '../../constants';\nimport { checkoutKeys } from './keys';\nimport type { EdxSessionResult } from '../../utils/provision';\nimport { getPlanPrice } from '../../utils/billingDetails';\nimport { buildStripeReturnUrl } from '../../utils/stripe';\nimport type {\n CheckoutClient, StripeLike, StripeElementLike, Cart, BillingInfo,\n CartBillingAddress, CartStatusResult, CheckoutConsent, BillingCycle, SupportedPaymentMethod,\n} from '../../types';\n\nclass CardValidationError extends Error {}\n\nfunction toCartAddress(b: BillingInfo): CartBillingAddress {\n return {\n tFirstName: b.firstName,\n tLastName: b.lastName,\n upaLine1: b.line1,\n upaCity: b.city,\n upaPostcode: b.zip,\n gadStateOrProvince: b.state,\n gadCountry: { iso2Code: b.country },\n };\n}\n\nfunction toStripeAddress(b: BillingInfo): Record<string, string | undefined> {\n return {\n line1: b.line1 || undefined,\n city: b.city || undefined,\n state: b.state || undefined,\n postal_code: b.zip || undefined,\n country: b.country || undefined,\n };\n}\n\nexport interface CheckoutMutationsCtx {\n client: CheckoutClient | null,\n sessionRef: RefObject<EdxSessionResult | null>,\n stripeRef: RefObject<StripeLike | null>,\n cardNumberElRef: RefObject<StripeElementLike | null>,\n billingRef: RefObject<BillingInfo | null>,\n /** Selected monthly/annual cycle at Place order time. */\n selectedCycleRef: RefObject<BillingCycle>,\n setError: (msg: string) => void,\n setCardError: (msg: string) => void,\n onCartCreated: (cart: Cart) => void,\n}\n\nexport interface PlaceOrderArgs {\n consent: CheckoutConsent,\n paymentMethod: SupportedPaymentMethod,\n}\n\nexport function useCheckoutMutations(ctx: CheckoutMutationsCtx) {\n const queryClient = useQueryClient();\n\n const optimisticConfirm = (cartBiId: string) => {\n queryClient.setQueryData<CartStatusResult>(checkoutKeys.status(cartBiId), (old) => {\n console.log('old optimisticConfirm', old);\n return {\n status: STATUS.CONFIRM,\n stripeSubscriptionId: old?.stripeSubscriptionId ?? null,\n stripeConfirmationRedirectUrl: old?.stripeConfirmationRedirectUrl ?? null,\n paypalApprovalUrl: old?.paypalApprovalUrl ?? null,\n lastComment: old?.lastComment ?? '',\n };\n });\n queryClient.invalidateQueries({ queryKey: checkoutKeys.status(cartBiId) });\n };\n\n const placeOrder = useMutation<Cart, Error, PlaceOrderArgs>({\n mutationFn: async ({ consent, paymentMethod }) => {\n const { client, billingRef } = ctx;\n if (!client) throw new Error('Checkout is not ready yet.');\n\n // Google Pay is not currently supported.\n // if (paymentMethod === 'googlepay') {\n // throw new Error('Google Pay is not supported yet. Please choose Card or PayPal.');\n // }\n\n const billing = billingRef.current;\n if (!billing) throw new Error('Billing information is not available. Please refresh and try again.');\n\n const session = ctx.sessionRef.current;\n if (!session) {\n throw new Error('Checkout session is not ready yet. Please wait a moment and try again.');\n }\n const { customerUid } = session;\n\n // ── Step 1: Fetch salable(product) uid + billing plans in parallel ─────────────\n const [productInfo, plansResult] = await Promise.all([\n client.getSalableUid('TWOU-SUB-PLAN-001'),\n client.getBillingPlans(),\n ]);\n const salableUid = productInfo.uid;\n const selectedCycle = ctx.selectedCycleRef.current ?? 'monthly';\n const selectedPlan = getPlanPrice(plansResult.plans, selectedCycle);\n if (!selectedPlan) {\n throw new Error(`No billing plan found for ${selectedCycle} billing.`);\n }\n const billingPlanUid = selectedPlan.uid;\n\n // ── Step 2: Create the cart ───────────────────────────────────────────\n const createdCart = await client.createCart({ customerUid, salableUid, billingPlanUid });\n ctx.onCartCreated(createdCart);\n\n // ── Step 3: Attach billing address + payment method to cart item ──────\n const { cartItemUid } = await client.getCartItem(createdCart.biId);\n\n if (paymentMethod === 'paypal') {\n // No card tokenization — PayPal issues a hosted approval redirect instead.\n await client.updateCartItem({\n cartItemUid,\n billingAddress: toCartAddress(billing),\n paypalEmail: session.email ?? null,\n });\n } else {\n const stripe = ctx.stripeRef.current;\n const card = ctx.cardNumberElRef.current;\n if (!stripe || !card) throw new Error('Checkout is not ready yet.');\n\n // Tokenize the card (browser → Stripe).\n const { paymentMethod: stripePaymentMethod, error } = await stripe.createPaymentMethod({\n type: 'card',\n card,\n billing_details: {\n name: `${billing.firstName} ${billing.lastName}`.trim(),\n address: toStripeAddress(billing),\n },\n });\n if (error || !stripePaymentMethod) {\n throw new CardValidationError(error?.message || 'There was a problem with your card.');\n }\n\n await client.updateCartItem({\n cartItemUid,\n billingAddress: toCartAddress(billing),\n paymentMethodId: stripePaymentMethod.id,\n });\n }\n\n // ── Step 4: Persist consent + hosted-payment return URL on the TwouCart BI ────\n await client.updateCartConsent({\n cartUid: createdCart.uid,\n consent,\n returnUrl: buildStripeReturnUrl(createdCart.biId),\n });\n\n // ── Step 5: Wait for the asynchronously-created workflow ──────────────\n await client.waitForCartBusinessProcess(createdCart.biId);\n\n // ── Step 6: Fire the backend workflow ─────────────────────────────────\n await client.placeOrder(createdCart.uid);\n\n return createdCart;\n },\n onSuccess: (cart) => {\n optimisticConfirm(cart.biId);\n },\n onError: (err) => {\n if (err instanceof CardValidationError) ctx.setCardError(err.message);\n else ctx.setError(err.message);\n },\n });\n\n return { placeOrder };\n}\n"]}
|
|
@@ -5,6 +5,12 @@ export interface CommonTrackingProps {
|
|
|
5
5
|
session_id?: string | null;
|
|
6
6
|
experimentation?: string | null;
|
|
7
7
|
device_type?: string | null;
|
|
8
|
+
subscription_start_date?: string | null;
|
|
9
|
+
subscription_end_date?: string | null;
|
|
10
|
+
subscription_trial_end_date?: string | null;
|
|
11
|
+
current_period_end?: string | null;
|
|
12
|
+
user_email?: string | null;
|
|
13
|
+
payment_method?: string | null;
|
|
8
14
|
}
|
|
9
15
|
export declare const setCommonTrackingProps: (props: CommonTrackingProps) => void;
|
|
10
16
|
export declare const getCommonTrackingProps: () => CommonTrackingProps;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAuthenticatedUser } from '@openedx/frontend-base';
|
|
1
2
|
let commonProps = {};
|
|
2
3
|
export const setCommonTrackingProps = (props) => {
|
|
3
4
|
commonProps = Object.assign(Object.assign({}, commonProps), props);
|
|
@@ -5,7 +6,7 @@ export const setCommonTrackingProps = (props) => {
|
|
|
5
6
|
export const getCommonTrackingProps = () => commonProps;
|
|
6
7
|
// Single place that maps the subs/init API response -> tracking props
|
|
7
8
|
export const mapSubsInitToTrackingProps = (data) => {
|
|
8
|
-
var _a, _b, _c;
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
9
10
|
return ({
|
|
10
11
|
free_trial_status: (_a = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _a === void 0 ? void 0 : _a.trialActive,
|
|
11
12
|
subscription_status: (_b = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _b === void 0 ? void 0 : _b.status,
|
|
@@ -13,6 +14,13 @@ export const mapSubsInitToTrackingProps = (data) => {
|
|
|
13
14
|
session_id: '',
|
|
14
15
|
experimentation: '',
|
|
15
16
|
device_type: '',
|
|
17
|
+
subscription_start_date: (_d = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _d === void 0 ? void 0 : _d.startDate,
|
|
18
|
+
subscription_end_date: (_e = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _e === void 0 ? void 0 : _e.endDate,
|
|
19
|
+
subscription_trial_end_date: (_f = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _f === void 0 ? void 0 : _f.trialEndDate,
|
|
20
|
+
current_period_end: (_g = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _g === void 0 ? void 0 : _g.currentPeriodEnd,
|
|
21
|
+
user_email: (_h = getAuthenticatedUser()) === null || _h === void 0 ? void 0 : _h.email,
|
|
22
|
+
payment_method: (_j = data === null || data === void 0 ? void 0 : data.userSubscription) === null || _j === void 0 ? void 0 : _j.paymentMethod,
|
|
23
|
+
// TODO: add marketing opt-in status field from the API response that should be tracked
|
|
16
24
|
});
|
|
17
25
|
};
|
|
18
26
|
//# sourceMappingURL=trackingContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trackingContext.js","sourceRoot":"","sources":["../../src/tracking/trackingContext.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"trackingContext.js","sourceRoot":"","sources":["../../src/tracking/trackingContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAgB9D,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,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}\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 // TODO: add marketing opt-in status field from the API response that should be tracked\n});\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -163,6 +163,7 @@ export interface CheckoutClient {
|
|
|
163
163
|
}>;
|
|
164
164
|
updateCartItem: (args: UpdateCartItemArgs) => Promise<void>;
|
|
165
165
|
updateCartConsent: (args: UpdateCartConsentArgs) => Promise<void>;
|
|
166
|
+
waitForCartBusinessProcess: (biId: string) => Promise<void>;
|
|
166
167
|
placeOrder: (cartUid: string) => Promise<unknown>;
|
|
167
168
|
getCartStatus: (biId: string) => Promise<CartStatusResult>;
|
|
168
169
|
findSubscriptionBiId: (biId: string) => Promise<SubscriptionDetails | null>;
|
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 PaymentMethod = 'card' | 'googlepay' | 'paypal';\n\nexport type SupportedPaymentMethod = Exclude<PaymentMethod, 'googlepay'>;\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 /** Stripe-hosted challenge URL for the checkout confirmation step. */\n stripeConfirmationRedirectUrl: string | null,\n /** PayPal-hosted approval URL for the same checkout confirmation step. */\n paypalApprovalUrl: 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 /** Payer email attached when the payment type is TwouPaypalPayment. */\n paypalEmail?: string | null,\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 /** Absolute checkout return URL stored in the backend's tStripeReturnUrl field. */\n returnUrl?: string | null,\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":"","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 PaymentMethod = 'card' | 'googlepay' | 'paypal';\n\nexport type SupportedPaymentMethod = Exclude<PaymentMethod, 'googlepay'>;\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 /** Stripe-hosted challenge URL for the checkout confirmation step. */\n stripeConfirmationRedirectUrl: string | null,\n /** PayPal-hosted approval URL for the same checkout confirmation step. */\n paypalApprovalUrl: 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 /** Payer email attached when the payment type is TwouPaypalPayment. */\n paypalEmail?: string | null,\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 /** Absolute checkout return URL stored in the backend's tStripeReturnUrl field. */\n returnUrl?: string | null,\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 waitForCartBusinessProcess: (biId: string) => 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"]}
|
package/dist/utils/auth.js
CHANGED
|
@@ -15,6 +15,7 @@ export function createCheckoutClient({ apiUrl }) {
|
|
|
15
15
|
getCartItem: (biId) => cart.getCartItem(gql, biId),
|
|
16
16
|
updateCartItem: (args) => cart.updateCartItem(gql, args),
|
|
17
17
|
updateCartConsent: (args) => cart.updateCartConsent(gql, args),
|
|
18
|
+
waitForCartBusinessProcess: (biId) => cart.waitForCartBusinessProcess(gql, biId),
|
|
18
19
|
placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),
|
|
19
20
|
getCartStatus: fetchStatus,
|
|
20
21
|
findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),
|
package/dist/utils/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,oBAAoB,CAClC,EAAE,MAAM,EAAwB;IAEhC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEpE,OAAO;QACL,GAAG;QACH,QAAQ;QACR,UAAU,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC;QACzD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC;QAClD,cAAc,EAAE,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC;QAC5E,iBAAiB,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC;QACrF,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;QACtD,aAAa,EAAE,WAAW;QAC1B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC;QACpE,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;QAC3D,eAAe,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,CAAC;QACrD,sBAAsB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,sBAAsB,CAAC,GAAG,CAAC;QACnE,uBAAuB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC;QACrE,eAAe,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * api/index.ts — composes the pieces into a single checkout client and\n * re-exports the API utilities.\n */\nimport { createGqlClient } from './graphqlClient';\nimport * as cart from './cartApi';\nimport * as bootstrap from './bootstrapApi';\nimport type {\n CheckoutClient, CartIds, UpdateCartItemArgs, UpdateCartConsentArgs,\n} from '../types';\n\ninterface CheckoutClientConfig {\n apiUrl: string,\n confirmIntentUrl?: string,\n}\n\nexport function createCheckoutClient(\n { apiUrl }: CheckoutClientConfig,\n): CheckoutClient {\n const { gql, setToken } = createGqlClient({ apiUrl });\n const fetchStatus = (biId: string) => cart.getCartStatus(gql, biId);\n\n return {\n gql,\n setToken,\n createCart: (vars: CartIds) => cart.createCart(gql, vars),\n getCartItem: (biId) => cart.getCartItem(gql, biId),\n updateCartItem: (args: UpdateCartItemArgs) => cart.updateCartItem(gql, args),\n updateCartConsent: (args: UpdateCartConsentArgs) => cart.updateCartConsent(gql, args),\n placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),\n getCartStatus: fetchStatus,\n findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),\n getSalableUid: (maId) => bootstrap.getSalableUid(gql, maId),\n getBillingPlans: () => bootstrap.getBillingPlans(gql),\n getActiveSubscriptions: () => bootstrap.getActiveSubscriptions(gql),\n isCurrentUserSubscriber: () => bootstrap.isCurrentUserSubscriber(gql),\n getCourseDetail: (courseKey) => bootstrap.getCourseDetail(gql, courseKey),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,oBAAoB,CAClC,EAAE,MAAM,EAAwB;IAEhC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEpE,OAAO;QACL,GAAG;QACH,QAAQ;QACR,UAAU,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC;QACzD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC;QAClD,cAAc,EAAE,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC;QAC5E,iBAAiB,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC;QACrF,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,GAAG,EAAE,IAAI,CAAC;QAChF,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;QACtD,aAAa,EAAE,WAAW;QAC1B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC;QACpE,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;QAC3D,eAAe,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,CAAC;QACrD,sBAAsB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,sBAAsB,CAAC,GAAG,CAAC;QACnE,uBAAuB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC;QACrE,eAAe,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * api/index.ts — composes the pieces into a single checkout client and\n * re-exports the API utilities.\n */\nimport { createGqlClient } from './graphqlClient';\nimport * as cart from './cartApi';\nimport * as bootstrap from './bootstrapApi';\nimport type {\n CheckoutClient, CartIds, UpdateCartItemArgs, UpdateCartConsentArgs,\n} from '../types';\n\ninterface CheckoutClientConfig {\n apiUrl: string,\n confirmIntentUrl?: string,\n}\n\nexport function createCheckoutClient(\n { apiUrl }: CheckoutClientConfig,\n): CheckoutClient {\n const { gql, setToken } = createGqlClient({ apiUrl });\n const fetchStatus = (biId: string) => cart.getCartStatus(gql, biId);\n\n return {\n gql,\n setToken,\n createCart: (vars: CartIds) => cart.createCart(gql, vars),\n getCartItem: (biId) => cart.getCartItem(gql, biId),\n updateCartItem: (args: UpdateCartItemArgs) => cart.updateCartItem(gql, args),\n updateCartConsent: (args: UpdateCartConsentArgs) => cart.updateCartConsent(gql, args),\n waitForCartBusinessProcess: (biId) => cart.waitForCartBusinessProcess(gql, biId),\n placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),\n getCartStatus: fetchStatus,\n findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),\n getSalableUid: (maId) => bootstrap.getSalableUid(gql, maId),\n getBillingPlans: () => bootstrap.getBillingPlans(gql),\n getActiveSubscriptions: () => bootstrap.getActiveSubscriptions(gql),\n isCurrentUserSubscriber: () => bootstrap.isCurrentUserSubscriber(gql),\n getCourseDetail: (courseKey) => bootstrap.getCourseDetail(gql, courseKey),\n };\n}\n"]}
|
package/dist/utils/cartApi.d.ts
CHANGED
|
@@ -9,8 +9,15 @@ export declare function getCartItem(gql: GqlRunner, biId: string): Promise<{
|
|
|
9
9
|
export declare function updateCartItem(gql: GqlRunner, { cartItemUid, billingAddress, paymentMethodId, paypalEmail }: UpdateCartItemArgs): Promise<void>;
|
|
10
10
|
/** Persist checkout consent checkboxes and the hosted-payment return URL onto the TwouCart BI. */
|
|
11
11
|
export declare function updateCartConsent(gql: GqlRunner, { cartUid, consent, returnUrl }: UpdateCartConsentArgs): Promise<void>;
|
|
12
|
+
interface WaitForCartBusinessProcessOptions {
|
|
13
|
+
intervalMs?: number;
|
|
14
|
+
maxAttempts?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Wait until the asynchronously-created workflow is attached to the cart. */
|
|
17
|
+
export declare function waitForCartBusinessProcess(gql: GqlRunner, biId: string, { intervalMs, maxAttempts, }?: WaitForCartBusinessProcessOptions): Promise<void>;
|
|
12
18
|
/** "Place order" — triggers the server-side workflow. */
|
|
13
19
|
export declare function placeOrder(gql: GqlRunner, cartUid: string): Promise<unknown>;
|
|
14
20
|
/** → current cart workflow status, Stripe details, and latest comment. */
|
|
15
21
|
export declare function getCartStatus(gql: GqlRunner, biId: string): Promise<CartStatusResult>;
|
|
16
22
|
export declare function findSubscriptionBiId(gql: GqlRunner, cartBiId: string): Promise<SubscriptionDetails | null>;
|
|
23
|
+
export {};
|
package/dist/utils/cartApi.js
CHANGED
|
@@ -12,7 +12,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
12
12
|
* Each takes the `gql` runner as its first argument so they stay pure and
|
|
13
13
|
* independently testable (mock `gql`, assert the variables).
|
|
14
14
|
*/
|
|
15
|
-
import { CREATE_CART, GET_CART_ITEM, UPDATE_CART_ITEM, UPDATE_CART, PLACE_ORDER, GET_CART_STATUS, FIND_SUBSCRIPTION, } from './queries';
|
|
15
|
+
import { CREATE_CART, GET_CART_ITEM, UPDATE_CART_ITEM, UPDATE_CART, PLACE_ORDER, GET_CART_BUSINESS_PROCESS, GET_CART_STATUS, FIND_SUBSCRIPTION, } from './queries';
|
|
16
16
|
/** createTwouCart → { biId, uid } */
|
|
17
17
|
export function createCart(gql_1, _a) {
|
|
18
18
|
return __awaiter(this, arguments, void 0, function* (gql, { customerUid, salableUid, billingPlanUid }) {
|
|
@@ -74,6 +74,23 @@ export function updateCartConsent(gql_1, _a) {
|
|
|
74
74
|
yield gql(UPDATE_CART, { input });
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
+
const CART_WORKFLOW_POLL_INTERVAL_MS = 250;
|
|
78
|
+
const CART_WORKFLOW_MAX_ATTEMPTS = 20;
|
|
79
|
+
/** Wait until the asynchronously-created workflow is attached to the cart. */
|
|
80
|
+
export function waitForCartBusinessProcess(gql_1, biId_1) {
|
|
81
|
+
return __awaiter(this, arguments, void 0, function* (gql, biId, { intervalMs = CART_WORKFLOW_POLL_INTERVAL_MS, maxAttempts = CART_WORKFLOW_MAX_ATTEMPTS, } = {}) {
|
|
82
|
+
var _a;
|
|
83
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
84
|
+
const data = yield gql(GET_CART_BUSINESS_PROCESS, { biId });
|
|
85
|
+
if (((_a = data === null || data === void 0 ? void 0 : data.getBusinessInteraction) === null || _a === void 0 ? void 0 : _a.bpBusinessProcess) != null)
|
|
86
|
+
return;
|
|
87
|
+
if (attempt < maxAttempts - 1) {
|
|
88
|
+
yield new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new Error('The cart is still being prepared. Please try placing your order again.');
|
|
92
|
+
});
|
|
93
|
+
}
|
|
77
94
|
/** "Place order" — triggers the server-side workflow. */
|
|
78
95
|
export function placeOrder(gql, cartUid) {
|
|
79
96
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cartApi.js","sourceRoot":"","sources":["../../src/utils/cartApi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/cartApi.ts — one function per checkout operation.\n * Each takes the `gql` runner as its first argument so they stay pure and\n * independently testable (mock `gql`, assert the variables).\n */\nimport {\n CREATE_CART, GET_CART_ITEM, UPDATE_CART_ITEM, UPDATE_CART,\n PLACE_ORDER, GET_CART_STATUS, FIND_SUBSCRIPTION,\n} from './queries';\nimport type {\n GqlRunner, Cart, CartIds, CartStatusResult, UpdateCartItemArgs,\n UpdateCartConsentArgs, Status, SubscriptionDetails,\n} from '../types';\n\n/** createTwouCart → { biId, uid } */\nexport async function createCart(gql: GqlRunner, { customerUid, salableUid, billingPlanUid }: CartIds): Promise<Cart> {\n const data = await gql(CREATE_CART, {\n input: {\n prPartyPrimary: { uid: customerUid },\n hiConsistsOf: [{ biiSalable: { uid: salableUid }, paybBillingPlan: { uid: billingPlanUid } }],\n },\n });\n return data.createTwouCart as Cart;\n}\n\n/** → { cartUid, cartItemUid } */\nexport async function getCartItem(gql: GqlRunner, biId: string): Promise<{ cartUid: string, cartItemUid: string }> {\n const data = await gql(GET_CART_ITEM, { biId });\n const bi = data.getBusinessInteraction;\n const cartUid = bi?.uid as string | undefined;\n const cartItemUid = bi?.hiConsistsOf?.[0]?.uid as string | undefined;\n\n if (!cartUid || !cartItemUid) {\n throw new Error(`Cart item not found for cart \"${biId}\".`);\n }\n\n return { cartUid, cartItemUid };\n}\n\nexport async function updateCartItem(\n gql: GqlRunner,\n { cartItemUid, billingAddress, paymentMethodId, paypalEmail }: UpdateCartItemArgs,\n): Promise<void> {\n const input: Record<string, unknown> = { uid: cartItemUid };\n // Interface-typed inputs accept exactly one key, named after the concrete\n // type, and all of its fields live inside it.\n if (billingAddress) input.paybBillingAddress = { _viaxUrbanPropertyAddress: { ...billingAddress } };\n if (paymentMethodId) {\n input.paybPayment = {\n _twouStripePayment: { tStripePaymentMethodId: paymentMethodId },\n };\n } else if (paypalEmail !== undefined) {\n input.paybPayment = {\n _twouPaypalPayment: paypalEmail ? { tPaypalEmail: paypalEmail } : {},\n };\n }\n await gql(UPDATE_CART_ITEM, { input });\n}\n\n/** Persist checkout consent checkboxes and the hosted-payment return URL onto the TwouCart BI. */\nexport async function updateCartConsent(\n gql: GqlRunner,\n { cartUid, consent, returnUrl }: UpdateCartConsentArgs,\n): Promise<void> {\n const input: Record<string, unknown> = {\n uid: cartUid,\n tConsentRecurring: consent.tConsentRecurring,\n tConsentUkCa: consent.tConsentUkCa,\n tConsentAt: consent.tConsentAt,\n tConsentText: consent.tConsentText,\n };\n if (returnUrl) input.tStripeReturnUrl = returnUrl;\n await gql(UPDATE_CART, { input });\n}\n\n/** \"Place order\" — triggers the server-side workflow. */\nexport async function placeOrder(gql: GqlRunner, cartUid: string): Promise<unknown> {\n const data = await gql(PLACE_ORDER, {\n input: {\n businessProcessable: { uid: cartUid },\n transitionCode: 'Sanction_Check',\n },\n });\n return data.startBusinessProcessableTransitionV2;\n}\n\n/** → current cart workflow status, Stripe details, and latest comment. */\nexport async function getCartStatus(gql: GqlRunner, biId: string): Promise<CartStatusResult> {\n const data = await gql(GET_CART_STATUS, { biId });\n const bi = data?.getBusinessInteraction || {};\n const comments: string[] = bi.cmComments?.edges?.map((e: { node: { comText: string } }) => e.node.comText) || [];\n return {\n status: (bi.bpStatus?.code ?? null) as Status | null,\n stripeSubscriptionId: bi.hiConsistsOf?.[0]?.tStripeSubscriptionId ?? null,\n stripeConfirmationRedirectUrl: bi.tStripeConfirmationRedirectUrl ?? null,\n paypalApprovalUrl: bi.tPaypalApprovalUrl ?? null,\n lastComment: comments.length ? comments[comments.length - 1] : '',\n };\n}\n\nexport async function findSubscriptionBiId(gql: GqlRunner, cartBiId: string): Promise<SubscriptionDetails | null> {\n try {\n const data = await gql(FIND_SUBSCRIPTION, { filter: `biRelatesTo.biId = '${cartBiId}'` });\n const node = data?.filterTwouSubscription?.edges?.[0]?.node;\n if (!node?.biId) return null;\n\n const item = node.hiConsistsOf?.[0];\n const payment = item?.paybPayment;\n\n return {\n biId: node.biId,\n // TwouSubscription exposes tTrialGranted / tTrialPeriod, not start/end dates.\n // Trial display dates are computed client-side via getTrialDateRange().\n trialStart: null,\n trialEnd: null,\n renewalType: node.tRenewalType ?? null,\n cardLast4: payment?.tPaymentMethodLast4 ?? null, // ← last four digits\n cardBrand: payment?.tPaymentMethodBrand ?? null, // ← card type (Visa, Mastercard etc)\n stripePaymentMethodId: payment?.tStripePaymentMethodId ?? null,\n planName: item?.paybBillingPlan?.bipOwnershipModel?.omName ?? null,\n };\n } catch {\n return null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cartApi.js","sourceRoot":"","sources":["../../src/utils/cartApi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/cartApi.ts — one function per checkout operation.\n * Each takes the `gql` runner as its first argument so they stay pure and\n * independently testable (mock `gql`, assert the variables).\n */\nimport {\n CREATE_CART, GET_CART_ITEM, UPDATE_CART_ITEM, UPDATE_CART,\n PLACE_ORDER, GET_CART_BUSINESS_PROCESS, GET_CART_STATUS, FIND_SUBSCRIPTION,\n} from './queries';\nimport type {\n GqlRunner, Cart, CartIds, CartStatusResult, UpdateCartItemArgs,\n UpdateCartConsentArgs, Status, SubscriptionDetails,\n} from '../types';\n\n/** createTwouCart → { biId, uid } */\nexport async function createCart(gql: GqlRunner, { customerUid, salableUid, billingPlanUid }: CartIds): Promise<Cart> {\n const data = await gql(CREATE_CART, {\n input: {\n prPartyPrimary: { uid: customerUid },\n hiConsistsOf: [{ biiSalable: { uid: salableUid }, paybBillingPlan: { uid: billingPlanUid } }],\n },\n });\n return data.createTwouCart as Cart;\n}\n\n/** → { cartUid, cartItemUid } */\nexport async function getCartItem(gql: GqlRunner, biId: string): Promise<{ cartUid: string, cartItemUid: string }> {\n const data = await gql(GET_CART_ITEM, { biId });\n const bi = data.getBusinessInteraction;\n const cartUid = bi?.uid as string | undefined;\n const cartItemUid = bi?.hiConsistsOf?.[0]?.uid as string | undefined;\n\n if (!cartUid || !cartItemUid) {\n throw new Error(`Cart item not found for cart \"${biId}\".`);\n }\n\n return { cartUid, cartItemUid };\n}\n\nexport async function updateCartItem(\n gql: GqlRunner,\n { cartItemUid, billingAddress, paymentMethodId, paypalEmail }: UpdateCartItemArgs,\n): Promise<void> {\n const input: Record<string, unknown> = { uid: cartItemUid };\n // Interface-typed inputs accept exactly one key, named after the concrete\n // type, and all of its fields live inside it.\n if (billingAddress) input.paybBillingAddress = { _viaxUrbanPropertyAddress: { ...billingAddress } };\n if (paymentMethodId) {\n input.paybPayment = {\n _twouStripePayment: { tStripePaymentMethodId: paymentMethodId },\n };\n } else if (paypalEmail !== undefined) {\n input.paybPayment = {\n _twouPaypalPayment: paypalEmail ? { tPaypalEmail: paypalEmail } : {},\n };\n }\n await gql(UPDATE_CART_ITEM, { input });\n}\n\n/** Persist checkout consent checkboxes and the hosted-payment return URL onto the TwouCart BI. */\nexport async function updateCartConsent(\n gql: GqlRunner,\n { cartUid, consent, returnUrl }: UpdateCartConsentArgs,\n): Promise<void> {\n const input: Record<string, unknown> = {\n uid: cartUid,\n tConsentRecurring: consent.tConsentRecurring,\n tConsentUkCa: consent.tConsentUkCa,\n tConsentAt: consent.tConsentAt,\n tConsentText: consent.tConsentText,\n };\n if (returnUrl) input.tStripeReturnUrl = returnUrl;\n await gql(UPDATE_CART, { input });\n}\n\nconst CART_WORKFLOW_POLL_INTERVAL_MS = 250;\nconst CART_WORKFLOW_MAX_ATTEMPTS = 20;\n\ninterface WaitForCartBusinessProcessOptions {\n intervalMs?: number,\n maxAttempts?: number,\n}\n\n/** Wait until the asynchronously-created workflow is attached to the cart. */\nexport async function waitForCartBusinessProcess(\n gql: GqlRunner,\n biId: string,\n {\n intervalMs = CART_WORKFLOW_POLL_INTERVAL_MS,\n maxAttempts = CART_WORKFLOW_MAX_ATTEMPTS,\n }: WaitForCartBusinessProcessOptions = {},\n): Promise<void> {\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n const data = await gql(GET_CART_BUSINESS_PROCESS, { biId });\n if (data?.getBusinessInteraction?.bpBusinessProcess != null) return;\n\n if (attempt < maxAttempts - 1) {\n await new Promise(resolve => setTimeout(resolve, intervalMs));\n }\n }\n\n throw new Error('The cart is still being prepared. Please try placing your order again.');\n}\n\n/** \"Place order\" — triggers the server-side workflow. */\nexport async function placeOrder(gql: GqlRunner, cartUid: string): Promise<unknown> {\n const data = await gql(PLACE_ORDER, {\n input: {\n businessProcessable: { uid: cartUid },\n transitionCode: 'Sanction_Check',\n },\n });\n return data.startBusinessProcessableTransitionV2;\n}\n\n/** → current cart workflow status, Stripe details, and latest comment. */\nexport async function getCartStatus(gql: GqlRunner, biId: string): Promise<CartStatusResult> {\n const data = await gql(GET_CART_STATUS, { biId });\n const bi = data?.getBusinessInteraction || {};\n const comments: string[] = bi.cmComments?.edges?.map((e: { node: { comText: string } }) => e.node.comText) || [];\n return {\n status: (bi.bpStatus?.code ?? null) as Status | null,\n stripeSubscriptionId: bi.hiConsistsOf?.[0]?.tStripeSubscriptionId ?? null,\n stripeConfirmationRedirectUrl: bi.tStripeConfirmationRedirectUrl ?? null,\n paypalApprovalUrl: bi.tPaypalApprovalUrl ?? null,\n lastComment: comments.length ? comments[comments.length - 1] : '',\n };\n}\n\nexport async function findSubscriptionBiId(gql: GqlRunner, cartBiId: string): Promise<SubscriptionDetails | null> {\n try {\n const data = await gql(FIND_SUBSCRIPTION, { filter: `biRelatesTo.biId = '${cartBiId}'` });\n const node = data?.filterTwouSubscription?.edges?.[0]?.node;\n if (!node?.biId) return null;\n\n const item = node.hiConsistsOf?.[0];\n const payment = item?.paybPayment;\n\n return {\n biId: node.biId,\n // TwouSubscription exposes tTrialGranted / tTrialPeriod, not start/end dates.\n // Trial display dates are computed client-side via getTrialDateRange().\n trialStart: null,\n trialEnd: null,\n renewalType: node.tRenewalType ?? null,\n cardLast4: payment?.tPaymentMethodLast4 ?? null, // ← last four digits\n cardBrand: payment?.tPaymentMethodBrand ?? null, // ← card type (Visa, Mastercard etc)\n stripePaymentMethodId: payment?.tStripePaymentMethodId ?? null,\n planName: item?.paybBillingPlan?.bipOwnershipModel?.omName ?? null,\n };\n } catch {\n return null;\n }\n}\n"]}
|
package/dist/utils/checkout.js
CHANGED
|
@@ -15,6 +15,7 @@ export function createCheckoutClient({ apiUrl }) {
|
|
|
15
15
|
getCartItem: (biId) => cart.getCartItem(gql, biId),
|
|
16
16
|
updateCartItem: (args) => cart.updateCartItem(gql, args),
|
|
17
17
|
updateCartConsent: (args) => cart.updateCartConsent(gql, args),
|
|
18
|
+
waitForCartBusinessProcess: (biId) => cart.waitForCartBusinessProcess(gql, biId),
|
|
18
19
|
placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),
|
|
19
20
|
getCartStatus: fetchStatus,
|
|
20
21
|
findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/utils/checkout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAS5C,MAAM,UAAU,oBAAoB,CAClC,EAAE,MAAM,EAAwB;IAEhC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEpE,OAAO;QACL,GAAG;QACH,QAAQ;QACR,UAAU,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC;QACzD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC;QAClD,cAAc,EAAE,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC;QAC5E,iBAAiB,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC;QACrF,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;QACtD,aAAa,EAAE,WAAW;QAC1B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC;QACpE,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;QAC3D,eAAe,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,CAAC;QACrD,sBAAsB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,sBAAsB,CAAC,GAAG,CAAC;QACnE,uBAAuB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC;QACrE,eAAe,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * api/index.ts — composes the pieces into a single checkout client and\n * re-exports the API utilities.\n */\nimport { createGqlClient } from './graphqlClient';\nimport * as cart from './cartApi';\nimport * as bootstrap from './bootstrapApi';\nimport type {\n CheckoutClient, CartIds, UpdateCartItemArgs, UpdateCartConsentArgs,\n} from '../types';\n\ninterface CheckoutClientConfig {\n apiUrl: string,\n}\n\nexport function createCheckoutClient(\n { apiUrl }: CheckoutClientConfig,\n): CheckoutClient {\n const { gql, setToken } = createGqlClient({ apiUrl });\n const fetchStatus = (biId: string) => cart.getCartStatus(gql, biId);\n\n return {\n gql,\n setToken,\n createCart: (vars: CartIds) => cart.createCart(gql, vars),\n getCartItem: (biId) => cart.getCartItem(gql, biId),\n updateCartItem: (args: UpdateCartItemArgs) => cart.updateCartItem(gql, args),\n updateCartConsent: (args: UpdateCartConsentArgs) => cart.updateCartConsent(gql, args),\n placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),\n getCartStatus: fetchStatus,\n findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),\n getSalableUid: (maId) => bootstrap.getSalableUid(gql, maId),\n getBillingPlans: () => bootstrap.getBillingPlans(gql),\n getActiveSubscriptions: () => bootstrap.getActiveSubscriptions(gql),\n isCurrentUserSubscriber: () => bootstrap.isCurrentUserSubscriber(gql),\n getCourseDetail: (courseKey) => bootstrap.getCourseDetail(gql, courseKey),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/utils/checkout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAS5C,MAAM,UAAU,oBAAoB,CAClC,EAAE,MAAM,EAAwB;IAEhC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAEpE,OAAO;QACL,GAAG;QACH,QAAQ;QACR,UAAU,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC;QACzD,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC;QAClD,cAAc,EAAE,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC;QAC5E,iBAAiB,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC;QACrF,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,GAAG,EAAE,IAAI,CAAC;QAChF,UAAU,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;QACtD,aAAa,EAAE,WAAW;QAC1B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC;QACpE,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;QAC3D,eAAe,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,CAAC;QACrD,sBAAsB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,sBAAsB,CAAC,GAAG,CAAC;QACnE,uBAAuB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC;QACrE,eAAe,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC;KAC1E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * api/index.ts — composes the pieces into a single checkout client and\n * re-exports the API utilities.\n */\nimport { createGqlClient } from './graphqlClient';\nimport * as cart from './cartApi';\nimport * as bootstrap from './bootstrapApi';\nimport type {\n CheckoutClient, CartIds, UpdateCartItemArgs, UpdateCartConsentArgs,\n} from '../types';\n\ninterface CheckoutClientConfig {\n apiUrl: string,\n}\n\nexport function createCheckoutClient(\n { apiUrl }: CheckoutClientConfig,\n): CheckoutClient {\n const { gql, setToken } = createGqlClient({ apiUrl });\n const fetchStatus = (biId: string) => cart.getCartStatus(gql, biId);\n\n return {\n gql,\n setToken,\n createCart: (vars: CartIds) => cart.createCart(gql, vars),\n getCartItem: (biId) => cart.getCartItem(gql, biId),\n updateCartItem: (args: UpdateCartItemArgs) => cart.updateCartItem(gql, args),\n updateCartConsent: (args: UpdateCartConsentArgs) => cart.updateCartConsent(gql, args),\n waitForCartBusinessProcess: (biId) => cart.waitForCartBusinessProcess(gql, biId),\n placeOrder: (cartUid) => cart.placeOrder(gql, cartUid),\n getCartStatus: fetchStatus,\n findSubscriptionBiId: (biId) => cart.findSubscriptionBiId(gql, biId),\n getSalableUid: (maId) => bootstrap.getSalableUid(gql, maId),\n getBillingPlans: () => bootstrap.getBillingPlans(gql),\n getActiveSubscriptions: () => bootstrap.getActiveSubscriptions(gql),\n isCurrentUserSubscriber: () => bootstrap.isCurrentUserSubscriber(gql),\n getCourseDetail: (courseKey) => bootstrap.getCourseDetail(gql, courseKey),\n };\n}\n"]}
|
package/dist/utils/queries.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export declare const UPDATE_CART = "mutation UpdateCart($input: TwouCartInput!)
|
|
|
19
19
|
/** Triggers the backend workflow to place the order. */
|
|
20
20
|
export declare const PLACE_ORDER = "mutation PlaceOrder($input: StartBusinessProcessableTransitionInputV2!) {\n startBusinessProcessableTransitionV2(input: $input) { uid bpStatus { code } }\n}";
|
|
21
21
|
export declare const GET_CART_ITEM = "query GetCartItem($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n uid\n hiConsistsOf { ... on TwouCartItem { uid } }\n }\n}";
|
|
22
|
+
/** Checks whether the server has attached the cart's workflow yet. */
|
|
23
|
+
export declare const GET_CART_BUSINESS_PROCESS = "query GetCartBusinessProcess($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n bpBusinessProcess { uid }\n }\n}";
|
|
22
24
|
export declare const GET_CART_STATUS = "query GetCartStatus($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n bpStatus { code }\n hiConsistsOf { ... on TwouCartItem { tStripeSubscriptionId } }\n ... on TwouCart {\n tStripeConfirmationRedirectUrl\n tPaypalApprovalUrl\n cmComments { edges { node { comText } } }\n }\n }\n}";
|
|
23
25
|
export declare const FIND_SUBSCRIPTION = "query FindSubscription($filter: String!) {\n filterTwouSubscription(_first: 1, _filter: $filter) {\n edges {\n node {\n biId\n tRenewalType\n hiConsistsOf {\n ... on TwouSubscriptionItem {\n paybBillingPlan {\n tStripePriceId\n bipOwnershipModel { omName }\n }\n paybPayment {\n ... on TwouStripePayment {\n tStripePaymentMethodId\n tPaymentMethodLast4\n tPaymentMethodBrand\n }\n }\n }\n }\n }\n }\n }\n}";
|
|
24
26
|
/** Fetch the viax customer uid by email using filterTwouCustomer. */
|
package/dist/utils/queries.js
CHANGED
|
@@ -34,6 +34,12 @@ export const GET_CART_ITEM = `query GetCartItem($biId: String!) {
|
|
|
34
34
|
hiConsistsOf { ... on TwouCartItem { uid } }
|
|
35
35
|
}
|
|
36
36
|
}`;
|
|
37
|
+
/** Checks whether the server has attached the cart's workflow yet. */
|
|
38
|
+
export const GET_CART_BUSINESS_PROCESS = `query GetCartBusinessProcess($biId: String!) {
|
|
39
|
+
getBusinessInteraction(biId: $biId) {
|
|
40
|
+
bpBusinessProcess { uid }
|
|
41
|
+
}
|
|
42
|
+
}`;
|
|
37
43
|
export const GET_CART_STATUS = `query GetCartStatus($biId: String!) {
|
|
38
44
|
getBusinessInteraction(biId: $biId) {
|
|
39
45
|
bpStatus { code }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/utils/queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AAEjF,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAG;;EAE9B,CAAC;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,wDAAwD;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,iFAAiF;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;EAK3B,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;EAU7B,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;EAwB/B,CAAC;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAC;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;EAWzB,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;EAe/B,CAAC;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,8BAA8B,GAAG;;EAE5C,CAAC;AAEH;0GAC0G;AAC1G,MAAM,CAAC,MAAM,8BAA8B,GAAG;;EAE5C,CAAC;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B/B,CAAC","sourcesContent":["/**\n * api/queries.ts — GraphQL documents for the checkout flow.\n * Kept as plain strings so they can be reused, logged, or tested in isolation.\n *\n * Mutation reference (from API doc):\n * updateTwouCustomer — toggle Stripe test clock on/off\n * createTwouCart — user proceeds to payment\n * updateTwouCartItem — attach billing plan / payment method to cart\n * updateTwouCart — persist auto-renewal consent (SUBS-228)\n * startBusinessProcessableTransitionV2 — place order\n * updateTwouCartItem — retry: attach new payment method\n */\n\n// ─── Mutations ────────────────────────────────────────────────────────────────\n\n/** Creates a new cart during checkout. */\nexport const CREATE_CART = `mutation CreateCart($input: TwouCartInput!) {\n createTwouCart(input: $input) { biId uid }\n}`;\n\n/** Updates a cart item — attach billing plan / payment method. */\nexport const UPDATE_CART_ITEM = `mutation UpdateCartItem($input: TwouCartItemInput!) {\n updateTwouCartItem(input: $input) { uid }\n}`;\n\n/** Persists auto-renewal consent fields on the TwouCart BI (SUBS-228). */\nexport const UPDATE_CART = `mutation UpdateCart($input: TwouCartInput!) {\n updateTwouCart(input: $input) { uid }\n}`;\n\n/** Triggers the backend workflow to place the order. */\nexport const PLACE_ORDER = `mutation PlaceOrder($input: StartBusinessProcessableTransitionInputV2!) {\n startBusinessProcessableTransitionV2(input: $input) { uid bpStatus { code } }\n}`;\n\n// ─── Queries ──────────────────────────────────────────────────────────────────\n\nexport const GET_CART_ITEM = `query GetCartItem($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n uid\n hiConsistsOf { ... on TwouCartItem { uid } }\n }\n}`;\n\nexport const GET_CART_STATUS = `query GetCartStatus($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n bpStatus { code }\n hiConsistsOf { ... on TwouCartItem { tStripeSubscriptionId } }\n ... on TwouCart {\n tStripeConfirmationRedirectUrl\n tPaypalApprovalUrl\n cmComments { edges { node { comText } } }\n }\n }\n}`;\n\nexport const FIND_SUBSCRIPTION = `query FindSubscription($filter: String!) {\n filterTwouSubscription(_first: 1, _filter: $filter) {\n edges {\n node {\n biId\n tRenewalType\n hiConsistsOf {\n ... on TwouSubscriptionItem {\n paybBillingPlan {\n tStripePriceId\n bipOwnershipModel { omName }\n }\n paybPayment {\n ... on TwouStripePayment {\n tStripePaymentMethodId\n tPaymentMethodLast4\n tPaymentMethodBrand\n }\n }\n }\n }\n }\n }\n }\n}`;\n\n/** Fetch the viax customer uid by email using filterTwouCustomer. */\nexport const GET_CUSTOMER = `query GetCustomer($filter: String!) {\n filterTwouCustomer(_first: 1, _filter: $filter) {\n edges {\n node {\n uid\n parId\n parParty {\n paName\n paContacts {\n edges {\n node {\n ... on EmailAddressContactMedium {\n email\n }\n }\n }\n }\n ... on Individual {\n indFirstName\n indLastName\n }\n }\n }\n }\n }\n}`;\n\n/** Fetch the TwouSubscriptionPlan uid to use as biiSalable in createTwouCart. */\nexport const GET_PRODUCT = `query GetProduct($maId: String!) {\n getProduct(maId: $maId) {\n maName\n uid\n ... on TwouSubscriptionPlan {\n saOwnershipModels {\n uid\n omName\n }\n }\n }\n}`;\n\nexport const GET_BILLING_PLANS = `query GetBillingPlans {\n filterCustomerBillingPlan(_first: 10) {\n edges {\n node {\n uid\n tStripePriceId\n tStripeAmount {\n amount\n units { code }\n }\n bipIsTemplate\n bipOwnershipModel { uid omName }\n }\n }\n }\n}`;\n\n/** Fetch the number of active subscriptions — unauthenticated. */\nexport const GET_ACTIVE_SUBSCRIPTIONS_STATE = `query activeSubscriptions {\n tActiveSubscriptionsState\n}`;\n\n/** Check whether the currently authenticated user already has an active subscription.\n * tIsCurrentUserSubscriber is a JSON scalar — returns the full object, no subfield selection allowed. */\nexport const GET_IS_CURRENT_USER_SUBSCRIBER = `query IsCurrentUserSubscriber {\n tIsCurrentUserSubscriber\n}`;\n\n/** Fetch a course for the enrollment card when ?course_run_key= is present. */\nexport const GET_COURSE_DETAIL = `query CourseDetail($filter: String!) {\n filterTwouCourse(_first: 1, _filter: $filter) {\n edges {\n node {\n maId\n maName\n maDescription\n tShortDescription\n imageUrl\n tCourseKey\n tBrandText\n tPrimarySubjectArea\n tLevelType\n tLanguage\n tPacingType { code }\n tDurationLow\n tDurationHigh\n tDurationUnit { code }\n tEffortLow\n tEffortHigh\n tEffortUnit { code }\n tUrlCourse\n tB2cSubscriptionInclusion\n tHasOfacRestrictions\n tCatalogActive\n }\n }\n }\n}`;\n"]}
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/utils/queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AAEjF,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAG;;EAE9B,CAAC;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,wDAAwD;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG;;EAEzB,CAAC;AAEH,iFAAiF;AAEjF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;EAK3B,CAAC;AAEH,sEAAsE;AACtE,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;EAIvC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;EAU7B,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;EAwB/B,CAAC;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAC;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;EAWzB,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;EAe/B,CAAC;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,8BAA8B,GAAG;;EAE5C,CAAC;AAEH;0GAC0G;AAC1G,MAAM,CAAC,MAAM,8BAA8B,GAAG;;EAE5C,CAAC;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B/B,CAAC","sourcesContent":["/**\n * api/queries.ts — GraphQL documents for the checkout flow.\n * Kept as plain strings so they can be reused, logged, or tested in isolation.\n *\n * Mutation reference (from API doc):\n * updateTwouCustomer — toggle Stripe test clock on/off\n * createTwouCart — user proceeds to payment\n * updateTwouCartItem — attach billing plan / payment method to cart\n * updateTwouCart — persist auto-renewal consent (SUBS-228)\n * startBusinessProcessableTransitionV2 — place order\n * updateTwouCartItem — retry: attach new payment method\n */\n\n// ─── Mutations ────────────────────────────────────────────────────────────────\n\n/** Creates a new cart during checkout. */\nexport const CREATE_CART = `mutation CreateCart($input: TwouCartInput!) {\n createTwouCart(input: $input) { biId uid }\n}`;\n\n/** Updates a cart item — attach billing plan / payment method. */\nexport const UPDATE_CART_ITEM = `mutation UpdateCartItem($input: TwouCartItemInput!) {\n updateTwouCartItem(input: $input) { uid }\n}`;\n\n/** Persists auto-renewal consent fields on the TwouCart BI (SUBS-228). */\nexport const UPDATE_CART = `mutation UpdateCart($input: TwouCartInput!) {\n updateTwouCart(input: $input) { uid }\n}`;\n\n/** Triggers the backend workflow to place the order. */\nexport const PLACE_ORDER = `mutation PlaceOrder($input: StartBusinessProcessableTransitionInputV2!) {\n startBusinessProcessableTransitionV2(input: $input) { uid bpStatus { code } }\n}`;\n\n// ─── Queries ──────────────────────────────────────────────────────────────────\n\nexport const GET_CART_ITEM = `query GetCartItem($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n uid\n hiConsistsOf { ... on TwouCartItem { uid } }\n }\n}`;\n\n/** Checks whether the server has attached the cart's workflow yet. */\nexport const GET_CART_BUSINESS_PROCESS = `query GetCartBusinessProcess($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n bpBusinessProcess { uid }\n }\n}`;\n\nexport const GET_CART_STATUS = `query GetCartStatus($biId: String!) {\n getBusinessInteraction(biId: $biId) {\n bpStatus { code }\n hiConsistsOf { ... on TwouCartItem { tStripeSubscriptionId } }\n ... on TwouCart {\n tStripeConfirmationRedirectUrl\n tPaypalApprovalUrl\n cmComments { edges { node { comText } } }\n }\n }\n}`;\n\nexport const FIND_SUBSCRIPTION = `query FindSubscription($filter: String!) {\n filterTwouSubscription(_first: 1, _filter: $filter) {\n edges {\n node {\n biId\n tRenewalType\n hiConsistsOf {\n ... on TwouSubscriptionItem {\n paybBillingPlan {\n tStripePriceId\n bipOwnershipModel { omName }\n }\n paybPayment {\n ... on TwouStripePayment {\n tStripePaymentMethodId\n tPaymentMethodLast4\n tPaymentMethodBrand\n }\n }\n }\n }\n }\n }\n }\n}`;\n\n/** Fetch the viax customer uid by email using filterTwouCustomer. */\nexport const GET_CUSTOMER = `query GetCustomer($filter: String!) {\n filterTwouCustomer(_first: 1, _filter: $filter) {\n edges {\n node {\n uid\n parId\n parParty {\n paName\n paContacts {\n edges {\n node {\n ... on EmailAddressContactMedium {\n email\n }\n }\n }\n }\n ... on Individual {\n indFirstName\n indLastName\n }\n }\n }\n }\n }\n}`;\n\n/** Fetch the TwouSubscriptionPlan uid to use as biiSalable in createTwouCart. */\nexport const GET_PRODUCT = `query GetProduct($maId: String!) {\n getProduct(maId: $maId) {\n maName\n uid\n ... on TwouSubscriptionPlan {\n saOwnershipModels {\n uid\n omName\n }\n }\n }\n}`;\n\nexport const GET_BILLING_PLANS = `query GetBillingPlans {\n filterCustomerBillingPlan(_first: 10) {\n edges {\n node {\n uid\n tStripePriceId\n tStripeAmount {\n amount\n units { code }\n }\n bipIsTemplate\n bipOwnershipModel { uid omName }\n }\n }\n }\n}`;\n\n/** Fetch the number of active subscriptions — unauthenticated. */\nexport const GET_ACTIVE_SUBSCRIPTIONS_STATE = `query activeSubscriptions {\n tActiveSubscriptionsState\n}`;\n\n/** Check whether the currently authenticated user already has an active subscription.\n * tIsCurrentUserSubscriber is a JSON scalar — returns the full object, no subfield selection allowed. */\nexport const GET_IS_CURRENT_USER_SUBSCRIBER = `query IsCurrentUserSubscriber {\n tIsCurrentUserSubscriber\n}`;\n\n/** Fetch a course for the enrollment card when ?course_run_key= is present. */\nexport const GET_COURSE_DETAIL = `query CourseDetail($filter: String!) {\n filterTwouCourse(_first: 1, _filter: $filter) {\n edges {\n node {\n maId\n maName\n maDescription\n tShortDescription\n imageUrl\n tCourseKey\n tBrandText\n tPrimarySubjectArea\n tLevelType\n tLanguage\n tPacingType { code }\n tDurationLow\n tDurationHigh\n tDurationUnit { code }\n tEffortLow\n tEffortHigh\n tEffortUnit { code }\n tUrlCourse\n tB2cSubscriptionInclusion\n tHasOfacRestrictions\n tCatalogActive\n }\n }\n }\n}`;\n"]}
|