@edx/frontend-app-subscription-manage 1.22.0 → 1.23.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.
@@ -5,9 +5,7 @@ import { ORDER_DETAILS_PATH } from '../../constants';
5
5
  import OrderHistoryCard from './OrderHistoryCard';
6
6
  const OrdersList = ({ orders, onViewReceipt }) => {
7
7
  const navigate = useNavigate();
8
- return (_jsx("ul", { className: "list-unstyled mb-0", role: "list", children: orders.map((order) => (_jsx("li", { className: "mb-3", role: "listitem", children: _jsx(OrderHistoryCard, { title: order.name, purchaseDate: new Date(order.purchasedAt).toLocaleDateString('en-US'), totalCost: getFormattedCurrency(order.total), orderNumber: order.orderNumber,
9
- // TODO: Enable when paymentMethodType is in the API response.
10
- isReceiptDisabled: false, onViewReceipt: () => onViewReceipt === null || onViewReceipt === void 0 ? void 0 : onViewReceipt(order), onViewOrderDetails: () => navigate(`${ORDER_DETAILS_PATH}/${encodeURIComponent(order.orderNumber)}`) }) }, order.orderId))) }));
8
+ return (_jsx("ul", { className: "list-unstyled mb-0", role: "list", children: orders.map((order) => (_jsx("li", { className: "mb-3", role: "listitem", children: _jsx(OrderHistoryCard, { title: order.name, purchaseDate: new Date(order.purchasedAt).toLocaleDateString('en-US'), totalCost: getFormattedCurrency(order.total), orderNumber: order.orderNumber, isReceiptDisabled: false, onViewReceipt: () => onViewReceipt === null || onViewReceipt === void 0 ? void 0 : onViewReceipt(order), onViewOrderDetails: () => navigate(`${ORDER_DETAILS_PATH}/${encodeURIComponent(order.orderNumber)}`) }) }, order.orderId))) }));
11
9
  };
12
10
  export default OrdersList;
13
11
  //# sourceMappingURL=OrderList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrderList.js","sourceRoot":"","sources":["../../../src/components/OrderHistory/OrderList.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,oBAAoB,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,GAAG,CAAC,EAAE,MAAM,EAAE,aAAa,EAAmB,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,OAAO,CACL,aAAI,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAC,MAAM,YAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,aAAwB,SAAS,EAAC,MAAM,EAAC,IAAI,EAAC,UAAU,YACtD,KAAC,gBAAgB,IACf,KAAK,EAAE,KAAK,CAAC,IAAI,EACjB,YAAY,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,EACrE,SAAS,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,EAC5C,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,8DAA8D;gBAC9D,iBAAiB,EAAE,KAAK,EACxB,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,KAAK,CAAC,EAC3C,kBAAkB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,kBAAkB,IAAI,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,GACpG,IAVK,KAAK,CAAC,OAAO,CAWjB,CACN,CAAC,GACC,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { useNavigate } from 'react-router-dom';\n\nimport getFormattedCurrency from '../../utils/currency';\nimport type { OrdersListProps } from '../../types';\nimport { ORDER_DETAILS_PATH } from '../../constants';\nimport OrderHistoryCard from './OrderHistoryCard';\n\nconst OrdersList = ({ orders, onViewReceipt }: OrdersListProps) => {\n const navigate = useNavigate();\n\n return (\n <ul className=\"list-unstyled mb-0\" role=\"list\">\n {orders.map((order) => (\n <li key={order.orderId} className=\"mb-3\" role=\"listitem\">\n <OrderHistoryCard\n title={order.name}\n purchaseDate={new Date(order.purchasedAt).toLocaleDateString('en-US')}\n totalCost={getFormattedCurrency(order.total)}\n orderNumber={order.orderNumber}\n // TODO: Enable when paymentMethodType is in the API response.\n isReceiptDisabled={false}\n onViewReceipt={() => onViewReceipt?.(order)}\n onViewOrderDetails={() => navigate(`${ORDER_DETAILS_PATH}/${encodeURIComponent(order.orderNumber)}`)}\n />\n </li>\n ))}\n </ul>\n );\n};\n\nexport default OrdersList;\n"]}
1
+ {"version":3,"file":"OrderList.js","sourceRoot":"","sources":["../../../src/components/OrderHistory/OrderList.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,oBAAoB,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,GAAG,CAAC,EAAE,MAAM,EAAE,aAAa,EAAmB,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,OAAO,CACL,aAAI,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAC,MAAM,YAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,aAAwB,SAAS,EAAC,MAAM,EAAC,IAAI,EAAC,UAAU,YACtD,KAAC,gBAAgB,IACf,KAAK,EAAE,KAAK,CAAC,IAAI,EACjB,YAAY,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,EACrE,SAAS,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,EAC5C,WAAW,EAAE,KAAK,CAAC,WAAW,EAC9B,iBAAiB,EAAE,KAAK,EACxB,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,KAAK,CAAC,EAC3C,kBAAkB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,kBAAkB,IAAI,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,GACpG,IATK,KAAK,CAAC,OAAO,CAUjB,CACN,CAAC,GACC,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { useNavigate } from 'react-router-dom';\n\nimport getFormattedCurrency from '../../utils/currency';\nimport type { OrdersListProps } from '../../types';\nimport { ORDER_DETAILS_PATH } from '../../constants';\nimport OrderHistoryCard from './OrderHistoryCard';\n\nconst OrdersList = ({ orders, onViewReceipt }: OrdersListProps) => {\n const navigate = useNavigate();\n\n return (\n <ul className=\"list-unstyled mb-0\" role=\"list\">\n {orders.map((order) => (\n <li key={order.orderId} className=\"mb-3\" role=\"listitem\">\n <OrderHistoryCard\n title={order.name}\n purchaseDate={new Date(order.purchasedAt).toLocaleDateString('en-US')}\n totalCost={getFormattedCurrency(order.total)}\n orderNumber={order.orderNumber}\n isReceiptDisabled={false}\n onViewReceipt={() => onViewReceipt?.(order)}\n onViewOrderDetails={() => navigate(`${ORDER_DETAILS_PATH}/${encodeURIComponent(order.orderNumber)}`)}\n />\n </li>\n ))}\n </ul>\n );\n};\n\nexport default OrdersList;\n"]}
@@ -9,13 +9,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { Alert, Spinner } from '@openedx/paragon';
12
- import { useIntl } from '@openedx/frontend-base';
12
+ import { getAppConfig, useIntl } from '@openedx/frontend-base';
13
+ import { appId } from '../../constants';
13
14
  import { getStripePaymentReceipt } from '../../data/services/orderHistory/orderHistory';
14
15
  import { usePurchaseHistoryQuery } from '../../data/hooks/useOrderHistoryQueries';
15
16
  import { useViaxClient, useViaxSession } from '../../data/hooks/useManageQueries';
16
17
  import OrdersList from './OrderList';
17
18
  import RefundNotice from '../RefundNotice/RefundNotice';
18
19
  import messages from './messages';
20
+ const getPaypalReceiptUrl = () => {
21
+ const config = getAppConfig(appId);
22
+ const paypalReceiptUrl = config.PAYPAL_RECEIPT_URL;
23
+ if (typeof paypalReceiptUrl !== 'string') {
24
+ return null;
25
+ }
26
+ return paypalReceiptUrl.trim() || null;
27
+ };
19
28
  /** One-off course and program purchases, shown in the payment history tab. */
20
29
  const OrderPurchases = () => {
21
30
  var _a;
@@ -25,13 +34,27 @@ const OrderPurchases = () => {
25
34
  const purchaseHistoryQuery = usePurchaseHistoryQuery(client, sessionReady);
26
35
  const orders = (_a = purchaseHistoryQuery.data) !== null && _a !== void 0 ? _a : [];
27
36
  const handleViewReceipt = (order) => __awaiter(void 0, void 0, void 0, function* () {
37
+ var _a, _b, _c;
28
38
  if (!client || !order.orderId) {
29
39
  return;
30
40
  }
31
41
  try {
32
- const receiptUrl = yield getStripePaymentReceipt(client.gql, order.orderId);
33
- if (receiptUrl) {
34
- window.open(receiptUrl, '_blank', 'noopener,noreferrer');
42
+ const paymentMethodType = ((_b = (_a = order.paymentMethod) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : '').toLowerCase();
43
+ const isNotAppleOrGooglePay = !((_c = order.paymentMethod) === null || _c === void 0 ? void 0 : _c.wallet);
44
+ if (paymentMethodType === 'paypal') {
45
+ const paypalReceiptUrl = getPaypalReceiptUrl();
46
+ if (!paypalReceiptUrl) {
47
+ console.error('PayPal receipt URL is not configured.');
48
+ return;
49
+ }
50
+ window.open(paypalReceiptUrl, '_blank', 'noopener,noreferrer');
51
+ return;
52
+ }
53
+ else if (paymentMethodType === 'card' && isNotAppleOrGooglePay) {
54
+ const receiptUrl = yield getStripePaymentReceipt(client.gql, order.orderId);
55
+ if (receiptUrl) {
56
+ window.open(receiptUrl, '_blank', 'noopener,noreferrer');
57
+ }
35
58
  }
36
59
  }
37
60
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"OrderPurchases.js","sourceRoot":"","sources":["../../../src/components/OrderHistory/OrderPurchases.tsx"],"names":[],"mappings":";;;;;;;;;;AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,YAAY,MAAM,8BAA8B,CAAC;AACxD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,8EAA8E;AAC9E,MAAM,cAAc,GAAa,GAAG,EAAE;;IACpC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,oBAAoB,GAAG,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,MAAA,oBAAoB,CAAC,IAAI,mCAAI,EAAE,CAAC;IAE/C,MAAM,iBAAiB,GAAG,CAAO,KAA0B,EAAE,EAAE;QAC7D,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5E,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAA,CAAC;IAEF,OAAO,CACL,mBACE,SAAS,EAAC,qBAAqB,qBACf,uBAAuB,eAC7B,QAAQ,eACP,oBAAoB,CAAC,SAAS,IAAI,oBAAoB,CAAC,UAAU,aAE5E,aAAI,EAAE,EAAC,uBAAuB,EAAC,SAAS,EAAC,iEAAiE,YACvG,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,GACzC,EAEJ,oBAAoB,CAAC,OAAO,IAAI,CAC/B,KAAC,KAAK,IAAC,OAAO,EAAC,QAAQ,YAAE,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAS,CAC/E,EAEA,CAAC,oBAAoB,CAAC,OAAO,IAAI,CAAC,oBAAoB,CAAC,SAAS,IAAI,CACnE,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,OAAO,IAAC,SAAS,EAAC,QAAQ,EAAC,gBAAgB,EAAE,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAI,GACnF,CACP,EAEA,oBAAoB,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CACxD,YAAG,SAAS,EAAC,6CAA6C,YACvD,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAClD,CACL,EAEA,oBAAoB,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CACtD,8BACE,KAAC,UAAU,IAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,GAAI,EAChE,KAAC,YAAY,KAAG,IACf,CACJ,IACO,CACX,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import React from 'react';\nimport { Alert, Spinner } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport type { PurchaseHistoryItem } from '../../types';\nimport { getStripePaymentReceipt } from '../../data/services/orderHistory/orderHistory';\nimport { usePurchaseHistoryQuery } from '../../data/hooks/useOrderHistoryQueries';\nimport { useViaxClient, useViaxSession } from '../../data/hooks/useManageQueries';\nimport OrdersList from './OrderList';\nimport RefundNotice from '../RefundNotice/RefundNotice';\nimport messages from './messages';\n\n/** One-off course and program purchases, shown in the payment history tab. */\nconst OrderPurchases: React.FC = () => {\n const { formatMessage } = useIntl();\n const client = useViaxClient();\n const { sessionReady } = useViaxSession(client);\n const purchaseHistoryQuery = usePurchaseHistoryQuery(client, sessionReady);\n const orders = purchaseHistoryQuery.data ?? [];\n\n const handleViewReceipt = async (order: PurchaseHistoryItem) => {\n if (!client || !order.orderId) {\n return;\n }\n\n try {\n const receiptUrl = await getStripePaymentReceipt(client.gql, order.orderId);\n if (receiptUrl) {\n window.open(receiptUrl, '_blank', 'noopener,noreferrer');\n }\n } catch (error) {\n console.error('Unable to load payment receipt.', error);\n }\n };\n\n return (\n <section\n className=\"manage-section mt-5\"\n aria-labelledby=\"order-purchases-title\"\n aria-live=\"polite\"\n aria-busy={purchaseHistoryQuery.isLoading || purchaseHistoryQuery.isFetching}\n >\n <h2 id=\"order-purchases-title\" className=\"manage-section__title h3 font-weight-bold text-primary-500 mb-1\">\n {formatMessage(messages.otherPurchasesTitle)}\n </h2>\n\n {purchaseHistoryQuery.isError && (\n <Alert variant=\"danger\">{formatMessage(messages.purchaseHistoryError)}</Alert>\n )}\n\n {!purchaseHistoryQuery.isError && !purchaseHistoryQuery.isSuccess && (\n <div className=\"d-flex justify-content-center py-4\">\n <Spinner animation=\"border\" screenReaderText={formatMessage(messages.loadingOrders)} />\n </div>\n )}\n\n {purchaseHistoryQuery.isSuccess && orders.length === 0 && (\n <p className=\"manage-section__subtitle text-gray-700 mb-3\">\n {formatMessage(messages.coursePurchasesEmptyMessage)}\n </p>\n )}\n\n {purchaseHistoryQuery.isSuccess && orders.length > 0 && (\n <>\n <OrdersList orders={orders} onViewReceipt={handleViewReceipt} />\n <RefundNotice />\n </>\n )}\n </section>\n );\n};\n\nexport default OrderPurchases;\n"]}
1
+ {"version":3,"file":"OrderPurchases.js","sourceRoot":"","sources":["../../../src/components/OrderHistory/OrderPurchases.tsx"],"names":[],"mappings":";;;;;;;;;;AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAG/D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,YAAY,MAAM,8BAA8B,CAAC;AACxD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,mBAAmB,GAAG,GAAkB,EAAE;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAoC,CAAC;IACtE,MAAM,gBAAgB,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAEnD,IAAI,OAAO,gBAAgB,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,gBAAgB,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AACzC,CAAC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,cAAc,GAAa,GAAG,EAAE;;IACpC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,oBAAoB,GAAG,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,MAAA,oBAAoB,CAAC,IAAI,mCAAI,EAAE,CAAC;IAE/C,MAAM,iBAAiB,GAAG,CAAO,KAA0B,EAAE,EAAE;;QAC7D,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,iBAAiB,GAAG,CAAC,MAAA,MAAA,KAAK,CAAC,aAAa,0CAAE,IAAI,mCAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YAC1E,MAAM,qBAAqB,GAAG,CAAC,CAAA,MAAA,KAAK,CAAC,aAAa,0CAAE,MAAM,CAAA,CAAC;YAE3D,IAAI,iBAAiB,KAAK,QAAQ,EAAE,CAAC;gBACnC,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;gBAC/C,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACtB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;oBACvD,OAAO;gBACT,CAAC;gBAED,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;iBAAM,IAAI,iBAAiB,KAAK,MAAM,IAAI,qBAAqB,EAAE,CAAC;gBACjE,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC5E,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAA,CAAC;IAEF,OAAO,CACL,mBACE,SAAS,EAAC,qBAAqB,qBACf,uBAAuB,eAC7B,QAAQ,eACP,oBAAoB,CAAC,SAAS,IAAI,oBAAoB,CAAC,UAAU,aAE5E,aAAI,EAAE,EAAC,uBAAuB,EAAC,SAAS,EAAC,iEAAiE,YACvG,aAAa,CAAC,QAAQ,CAAC,mBAAmB,CAAC,GACzC,EAEJ,oBAAoB,CAAC,OAAO,IAAI,CAC/B,KAAC,KAAK,IAAC,OAAO,EAAC,QAAQ,YAAE,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAS,CAC/E,EAEA,CAAC,oBAAoB,CAAC,OAAO,IAAI,CAAC,oBAAoB,CAAC,SAAS,IAAI,CACnE,cAAK,SAAS,EAAC,oCAAoC,YACjD,KAAC,OAAO,IAAC,SAAS,EAAC,QAAQ,EAAC,gBAAgB,EAAE,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAI,GACnF,CACP,EAEA,oBAAoB,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CACxD,YAAG,SAAS,EAAC,6CAA6C,YACvD,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAClD,CACL,EAEA,oBAAoB,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CACtD,8BACE,KAAC,UAAU,IAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,iBAAiB,GAAI,EAChE,KAAC,YAAY,KAAG,IACf,CACJ,IACO,CACX,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import React from 'react';\nimport { Alert, Spinner } from '@openedx/paragon';\nimport { getAppConfig, useIntl } from '@openedx/frontend-base';\n\nimport type { PurchaseHistoryItem } from '../../types';\nimport { appId } from '../../constants';\nimport { getStripePaymentReceipt } from '../../data/services/orderHistory/orderHistory';\nimport { usePurchaseHistoryQuery } from '../../data/hooks/useOrderHistoryQueries';\nimport { useViaxClient, useViaxSession } from '../../data/hooks/useManageQueries';\nimport OrdersList from './OrderList';\nimport RefundNotice from '../RefundNotice/RefundNotice';\nimport messages from './messages';\n\nconst getPaypalReceiptUrl = (): string | null => {\n const config = getAppConfig(appId) as { PAYPAL_RECEIPT_URL?: string };\n const paypalReceiptUrl = config.PAYPAL_RECEIPT_URL;\n\n if (typeof paypalReceiptUrl !== 'string') {\n return null;\n }\n\n return paypalReceiptUrl.trim() || null;\n};\n\n/** One-off course and program purchases, shown in the payment history tab. */\nconst OrderPurchases: React.FC = () => {\n const { formatMessage } = useIntl();\n const client = useViaxClient();\n const { sessionReady } = useViaxSession(client);\n const purchaseHistoryQuery = usePurchaseHistoryQuery(client, sessionReady);\n const orders = purchaseHistoryQuery.data ?? [];\n\n const handleViewReceipt = async (order: PurchaseHistoryItem) => {\n if (!client || !order.orderId) {\n return;\n }\n\n try {\n const paymentMethodType = (order.paymentMethod?.type ?? '').toLowerCase();\n const isNotAppleOrGooglePay = !order.paymentMethod?.wallet;\n\n if (paymentMethodType === 'paypal') {\n const paypalReceiptUrl = getPaypalReceiptUrl();\n if (!paypalReceiptUrl) {\n console.error('PayPal receipt URL is not configured.');\n return;\n }\n\n window.open(paypalReceiptUrl, '_blank', 'noopener,noreferrer');\n return;\n } else if (paymentMethodType === 'card' && isNotAppleOrGooglePay) {\n const receiptUrl = await getStripePaymentReceipt(client.gql, order.orderId);\n if (receiptUrl) {\n window.open(receiptUrl, '_blank', 'noopener,noreferrer');\n }\n }\n } catch (error) {\n console.error('Unable to load payment receipt.', error);\n }\n };\n\n return (\n <section\n className=\"manage-section mt-5\"\n aria-labelledby=\"order-purchases-title\"\n aria-live=\"polite\"\n aria-busy={purchaseHistoryQuery.isLoading || purchaseHistoryQuery.isFetching}\n >\n <h2 id=\"order-purchases-title\" className=\"manage-section__title h3 font-weight-bold text-primary-500 mb-1\">\n {formatMessage(messages.otherPurchasesTitle)}\n </h2>\n\n {purchaseHistoryQuery.isError && (\n <Alert variant=\"danger\">{formatMessage(messages.purchaseHistoryError)}</Alert>\n )}\n\n {!purchaseHistoryQuery.isError && !purchaseHistoryQuery.isSuccess && (\n <div className=\"d-flex justify-content-center py-4\">\n <Spinner animation=\"border\" screenReaderText={formatMessage(messages.loadingOrders)} />\n </div>\n )}\n\n {purchaseHistoryQuery.isSuccess && orders.length === 0 && (\n <p className=\"manage-section__subtitle text-gray-700 mb-3\">\n {formatMessage(messages.coursePurchasesEmptyMessage)}\n </p>\n )}\n\n {purchaseHistoryQuery.isSuccess && orders.length > 0 && (\n <>\n <OrdersList orders={orders} onViewReceipt={handleViewReceipt} />\n <RefundNotice />\n </>\n )}\n </section>\n );\n};\n\nexport default OrderPurchases;\n"]}
package/dist/types.d.ts CHANGED
@@ -115,7 +115,12 @@ export interface PurchaseHistoryItem {
115
115
  orderNumber: string;
116
116
  purchasedAt: string;
117
117
  paymentIntentId?: string;
118
- paymentMethodType?: string;
118
+ paymentMethod?: {
119
+ type?: string;
120
+ brand?: string;
121
+ last4?: string;
122
+ wallet?: string;
123
+ } | null;
119
124
  name: string;
120
125
  total: {
121
126
  amount: number;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * Manage Subscription — domain types for Viax subscriber + enrollment data.\n */\n\n/** GraphQL runner used by VIAX fetchers. */\nexport type GqlRunner = (\n query: string,\n variables?: Record<string, unknown>,\n) => Promise<any>;\n\n/** Result of `tIsCurrentUserSubscriber` (JSON scalar). */\nexport interface CurrentUserSubscriberResult {\n /** Has/expects access — drive manage vs upsell messaging. */\n isSubscriber: boolean,\n /** Enrollable right now (ACTIVE / TRIAL_ACTIVE). */\n canEnroll: boolean,\n subscriptionBiId: string | null,\n /**\n * Every subscription the learner has held (all statuses, newest first),\n * e.g. a cancelled Stripe one plus a newer PayPal one. Payment history\n * lists invoices across all of them. Empty until the API returns it.\n */\n subscriptionBiIds?: string[],\n status: string | null,\n currentPeriodEnd: string | null,\n subscriptionStartDate: string | null,\n subscriptionEndDate: string | null,\n /**\n * Billing cycle / plan label used by UI (from `billingFrequency`,\n * `renewalType`, or `planName` on the API payload).\n */\n renewalType?: string | null,\n /** Optional cancel timestamp when present. */\n canceledAt?: string | null,\n /** Optional price display amount when present. */\n amount?: string | null,\n currency?: string | null,\n /**\n * Billing-plan fallback fields used when `renewalType` is missing\n * (e.g. PayPal payloads). See `resolvePlanLabel`.\n */\n billingPlanUid?: string | null,\n interval?: string | null,\n billingInterval?: string | null,\n bipOwnershipModel?: { uid?: string, omName?: string } | null,\n}\n\n/** Normalized enrollment for the cancel confirmation course list. */\nexport interface SubscriptionEnrollment {\n biId: string,\n courseMaId: string | null,\n courseName: string | null,\n courseSlug: string | null,\n /** Course card / thumbnail image. */\n imageUrl: string | null,\n orgName: string | null,\n orgLogoUrl: string | null,\n courseRunKey: string | null,\n /** TwouEnrollment bpStatus.code (ACTIVE, COMPLETED, …). */\n status: string | null,\n /** True when the enrollment has a certificate id and/or URL. */\n hasCertificate: boolean,\n /** Absolute certificate link (`COURSES_BASE_URL` + `tCertificateUrl`). */\n certificateUrl: string | null,\n}\n\nexport type PaymentProcessor = 'stripe' | 'paypal';\n\n/** Normalized invoice row for the Payment history tab. */\nexport interface PaymentHistoryItem {\n biId: string,\n /** Display order number, e.g. EDX-BI3X25N5SY30OSIK */\n orderNumber: string,\n stripeInvoiceId: string | null,\n /** PayPal sale id, or `trial:<PayPal subscription id>` for a $0 trial row. */\n paypalInvoiceId: string | null,\n /** Which processor billed this invoice; null when neither id is set. */\n paymentProcessor: PaymentProcessor | null,\n status: string | null,\n billDate: string | null,\n periodStart: string | null,\n periodEnd: string | null,\n /** Charged amount in major currency units (e.g. 59.00). */\n amount: number,\n currency: string,\n isTrial: boolean,\n}\n\n/** UI view derived from subscriber status. */\nexport type SubscriptionView =\n | 'none'\n | 'active'\n | 'canceled_access'\n | 'canceled_expired';\n\nexport type ManageTab = 'subscription' | 'payment-history';\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport interface BillingPlanOwnershipModel {\n uid: string,\n omName: string,\n}\n\n/** Normalized row from `filterCustomerBillingPlan`. */\nexport interface BillingPlan {\n uid: string,\n stripePriceId: string,\n /** Price amount e.g. \"39.99\" */\n amount: string,\n /** Currency code e.g. \"USD\" */\n currency: string,\n isTemplate: boolean,\n ownershipModel: BillingPlanOwnershipModel,\n}\n\nexport interface BillingPlansResult {\n plans: BillingPlan[],\n}\n\n/** One course line on a program purchase receipt. */\nexport interface PurchaseHistoryCourse {\n courseId: string,\n name: string,\n price: number,\n discountAmount: number,\n}\n\n/** One-off course or program purchase from `tOrderHistory.orders`. */\nexport interface PurchaseHistoryItem {\n orderId: string,\n orderNumber: string,\n purchasedAt: string,\n paymentIntentId?: string,\n paymentMethodType?: string,\n name: string,\n total: {\n amount: number,\n currency: string,\n },\n /** Set when the payload reports a program purchase. */\n itemType?: 'course' | 'program',\n courses?: PurchaseHistoryCourse[],\n}\n\nexport interface OrdersListProps {\n orders: PurchaseHistoryItem[],\n onViewReceipt?: (order: PurchaseHistoryItem) => void,\n}\n\nexport interface MoneyAmount {\n amount: number,\n currency: string,\n}\n\n/** One line on a program order details payload. */\nexport interface OrderProgramItem {\n productId?: string,\n courseRunKey?: string,\n name: string,\n price?: MoneyAmount,\n discount?: MoneyAmount,\n total?: MoneyAmount,\n}\n\n/** Normalized `tOrderDetails` payload for the order details page. */\nexport interface OrderDetailsData {\n orderId: string,\n orderNumber: string,\n purchasedAt: string,\n paymentIntentId: string,\n name: string,\n subtotalAmount?: MoneyAmount,\n itemPriceAmount?: MoneyAmount,\n discountCode?: string | null,\n total: MoneyAmount,\n discountAmount?: MoneyAmount,\n itemType: 'course' | 'program',\n items?: OrderProgramItem[],\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * Manage Subscription — domain types for Viax subscriber + enrollment data.\n */\n\n/** GraphQL runner used by VIAX fetchers. */\nexport type GqlRunner = (\n query: string,\n variables?: Record<string, unknown>,\n) => Promise<any>;\n\n/** Result of `tIsCurrentUserSubscriber` (JSON scalar). */\nexport interface CurrentUserSubscriberResult {\n /** Has/expects access — drive manage vs upsell messaging. */\n isSubscriber: boolean,\n /** Enrollable right now (ACTIVE / TRIAL_ACTIVE). */\n canEnroll: boolean,\n subscriptionBiId: string | null,\n /**\n * Every subscription the learner has held (all statuses, newest first),\n * e.g. a cancelled Stripe one plus a newer PayPal one. Payment history\n * lists invoices across all of them. Empty until the API returns it.\n */\n subscriptionBiIds?: string[],\n status: string | null,\n currentPeriodEnd: string | null,\n subscriptionStartDate: string | null,\n subscriptionEndDate: string | null,\n /**\n * Billing cycle / plan label used by UI (from `billingFrequency`,\n * `renewalType`, or `planName` on the API payload).\n */\n renewalType?: string | null,\n /** Optional cancel timestamp when present. */\n canceledAt?: string | null,\n /** Optional price display amount when present. */\n amount?: string | null,\n currency?: string | null,\n /**\n * Billing-plan fallback fields used when `renewalType` is missing\n * (e.g. PayPal payloads). See `resolvePlanLabel`.\n */\n billingPlanUid?: string | null,\n interval?: string | null,\n billingInterval?: string | null,\n bipOwnershipModel?: { uid?: string, omName?: string } | null,\n}\n\n/** Normalized enrollment for the cancel confirmation course list. */\nexport interface SubscriptionEnrollment {\n biId: string,\n courseMaId: string | null,\n courseName: string | null,\n courseSlug: string | null,\n /** Course card / thumbnail image. */\n imageUrl: string | null,\n orgName: string | null,\n orgLogoUrl: string | null,\n courseRunKey: string | null,\n /** TwouEnrollment bpStatus.code (ACTIVE, COMPLETED, …). */\n status: string | null,\n /** True when the enrollment has a certificate id and/or URL. */\n hasCertificate: boolean,\n /** Absolute certificate link (`COURSES_BASE_URL` + `tCertificateUrl`). */\n certificateUrl: string | null,\n}\n\nexport type PaymentProcessor = 'stripe' | 'paypal';\n\n/** Normalized invoice row for the Payment history tab. */\nexport interface PaymentHistoryItem {\n biId: string,\n /** Display order number, e.g. EDX-BI3X25N5SY30OSIK */\n orderNumber: string,\n stripeInvoiceId: string | null,\n /** PayPal sale id, or `trial:<PayPal subscription id>` for a $0 trial row. */\n paypalInvoiceId: string | null,\n /** Which processor billed this invoice; null when neither id is set. */\n paymentProcessor: PaymentProcessor | null,\n status: string | null,\n billDate: string | null,\n periodStart: string | null,\n periodEnd: string | null,\n /** Charged amount in major currency units (e.g. 59.00). */\n amount: number,\n currency: string,\n isTrial: boolean,\n}\n\n/** UI view derived from subscriber status. */\nexport type SubscriptionView =\n | 'none'\n | 'active'\n | 'canceled_access'\n | 'canceled_expired';\n\nexport type ManageTab = 'subscription' | 'payment-history';\n\nexport type BillingCycle = 'monthly' | 'annual';\n\nexport interface BillingPlanOwnershipModel {\n uid: string,\n omName: string,\n}\n\n/** Normalized row from `filterCustomerBillingPlan`. */\nexport interface BillingPlan {\n uid: string,\n stripePriceId: string,\n /** Price amount e.g. \"39.99\" */\n amount: string,\n /** Currency code e.g. \"USD\" */\n currency: string,\n isTemplate: boolean,\n ownershipModel: BillingPlanOwnershipModel,\n}\n\nexport interface BillingPlansResult {\n plans: BillingPlan[],\n}\n\n/** One course line on a program purchase receipt. */\nexport interface PurchaseHistoryCourse {\n courseId: string,\n name: string,\n price: number,\n discountAmount: number,\n}\n\n/** One-off course or program purchase from `tOrderHistory.orders`. */\nexport interface PurchaseHistoryItem {\n orderId: string,\n orderNumber: string,\n purchasedAt: string,\n paymentIntentId?: string,\n paymentMethod?: {\n type?: string,\n brand?: string,\n last4?: string,\n wallet?: string,\n } | null,\n name: string,\n total: {\n amount: number,\n currency: string,\n },\n /** Set when the payload reports a program purchase. */\n itemType?: 'course' | 'program',\n courses?: PurchaseHistoryCourse[],\n}\n\nexport interface OrdersListProps {\n orders: PurchaseHistoryItem[],\n onViewReceipt?: (order: PurchaseHistoryItem) => void,\n}\n\nexport interface MoneyAmount {\n amount: number,\n currency: string,\n}\n\n/** One line on a program order details payload. */\nexport interface OrderProgramItem {\n productId?: string,\n courseRunKey?: string,\n name: string,\n price?: MoneyAmount,\n discount?: MoneyAmount,\n total?: MoneyAmount,\n}\n\n/** Normalized `tOrderDetails` payload for the order details page. */\nexport interface OrderDetailsData {\n orderId: string,\n orderNumber: string,\n purchasedAt: string,\n paymentIntentId: string,\n name: string,\n subtotalAmount?: MoneyAmount,\n itemPriceAmount?: MoneyAmount,\n discountCode?: string | null,\n total: MoneyAmount,\n discountAmount?: MoneyAmount,\n itemType: 'course' | 'program',\n items?: OrderProgramItem[],\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edx/frontend-app-subscription-manage",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "description": "Subscription Manage Frontend application",
5
5
  "repository": {
6
6
  "type": "git",