@openrails/billing-ui 0.248.1 → 0.250.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/CHANGELOG.md +37 -0
- package/README.md +40 -35
- package/dist/account/account-billing.d.ts +2 -2
- package/dist/account/cancel-dialog.d.ts +2 -2
- package/dist/account/change-card-dialog.d.ts +2 -2
- package/dist/account/payment-history.d.ts +2 -2
- package/dist/account/payment-methods-panel.d.ts +2 -2
- package/dist/account/section.d.ts +2 -2
- package/dist/account/subscriptions-panel.d.ts +2 -2
- package/dist/admin/context.d.ts +2 -2
- package/dist/admin/lib/queries.d.ts +1 -1
- package/dist/admin/messages.d.ts +3 -3
- package/dist/admin/pages/catalog/psp-links.d.ts +1 -1
- package/dist/admin/theme.d.ts +2 -2
- package/dist/admin/types.d.ts +2 -2
- package/dist/{admin-attempts-lAoW-Urd.js → admin-attempts-DxRHTODq.js} +8 -8
- package/dist/{admin-attempts-lAoW-Urd.js.map → admin-attempts-DxRHTODq.js.map} +1 -1
- package/dist/{admin-auth-DQGHtt0j.js → admin-auth-CiuZ-Hlm.js} +2 -2
- package/dist/{admin-auth-DQGHtt0j.js.map → admin-auth-CiuZ-Hlm.js.map} +1 -1
- package/dist/{admin-badge-DR5-1qd8.js → admin-badge-VCGbnfiN.js} +2 -2
- package/dist/{admin-badge-DR5-1qd8.js.map → admin-badge-VCGbnfiN.js.map} +1 -1
- package/dist/{admin-button-CTL3DgOt.js → admin-button-Oip73Plq.js} +2 -2
- package/dist/{admin-button-CTL3DgOt.js.map → admin-button-Oip73Plq.js.map} +1 -1
- package/dist/{admin-capabilities-BuigAgtm.js → admin-capabilities-BGv7oG8v.js} +2 -2
- package/dist/{admin-capabilities-BuigAgtm.js.map → admin-capabilities-BGv7oG8v.js.map} +1 -1
- package/dist/{admin-card-bzAks3-3.js → admin-card-DGbi6ZHZ.js} +2 -2
- package/dist/{admin-card-bzAks3-3.js.map → admin-card-DGbi6ZHZ.js.map} +1 -1
- package/dist/{admin-catalog-CK6CM9I2.js → admin-catalog-3pPEAuDY.js} +19 -19
- package/dist/{admin-catalog-CK6CM9I2.js.map → admin-catalog-3pPEAuDY.js.map} +1 -1
- package/dist/{admin-customers-D8u5gq3M.js → admin-customers-cnKMEV4q.js} +6 -6
- package/dist/{admin-customers-D8u5gq3M.js.map → admin-customers-cnKMEV4q.js.map} +1 -1
- package/dist/{admin-dashboard-DqqFjOzq.js → admin-dashboard-DfSsUyo-.js} +14 -14
- package/dist/{admin-dashboard-DqqFjOzq.js.map → admin-dashboard-DfSsUyo-.js.map} +1 -1
- package/dist/{admin-data-table-qfXLOFmN.js → admin-data-table-CgeWv__T.js} +6 -6
- package/dist/{admin-data-table-qfXLOFmN.js.map → admin-data-table-CgeWv__T.js.map} +1 -1
- package/dist/{admin-detail-X82kR2f7.js → admin-detail-BATuJjVs.js} +12 -12
- package/dist/{admin-detail-X82kR2f7.js.map → admin-detail-BATuJjVs.js.map} +1 -1
- package/dist/{admin-detail-DUAJQg8G.js → admin-detail-Cq59e14B.js} +15 -15
- package/dist/{admin-detail-DUAJQg8G.js.map → admin-detail-Cq59e14B.js.map} +1 -1
- package/dist/{admin-detail-BHe51ma9.js → admin-detail-DG-YaHhS.js} +11 -11
- package/dist/{admin-detail-BHe51ma9.js.map → admin-detail-DG-YaHhS.js.map} +1 -1
- package/dist/{admin-detail-CGOyqs7s.js → admin-detail-Dc7rU4mM.js} +15 -15
- package/dist/{admin-detail-CGOyqs7s.js.map → admin-detail-Dc7rU4mM.js.map} +1 -1
- package/dist/{admin-dialog-BjuKI5Hp.js → admin-dialog-Ffx95AIT.js} +3 -3
- package/dist/{admin-dialog-BjuKI5Hp.js.map → admin-dialog-Ffx95AIT.js.map} +1 -1
- package/dist/{admin-dom-uMmZzRvU.js → admin-dom-lnNSQ7ke.js} +4 -4
- package/dist/{admin-dom-uMmZzRvU.js.map → admin-dom-lnNSQ7ke.js.map} +1 -1
- package/dist/{admin-dropdown-menu-BW1D_h6s.js → admin-dropdown-menu-CCiW4-oz.js} +2 -2
- package/dist/{admin-dropdown-menu-BW1D_h6s.js.map → admin-dropdown-menu-CCiW4-oz.js.map} +1 -1
- package/dist/{admin-fact-card-DO_fHosg.js → admin-fact-card-D6mZgxpN.js} +2 -2
- package/dist/{admin-fact-card-DO_fHosg.js.map → admin-fact-card-D6mZgxpN.js.map} +1 -1
- package/dist/{admin-health-B4jN2LwR.js → admin-health-CvJX9prw.js} +13 -13
- package/dist/{admin-health-B4jN2LwR.js.map → admin-health-CvJX9prw.js.map} +1 -1
- package/dist/{admin-input-CcfQfJFN.js → admin-input-DO5lvCLL.js} +2 -2
- package/dist/{admin-input-CcfQfJFN.js.map → admin-input-DO5lvCLL.js.map} +1 -1
- package/dist/{admin-label-BiEN5cjb.js → admin-label-BzJpr3lg.js} +2 -2
- package/dist/{admin-label-BiEN5cjb.js.map → admin-label-BzJpr3lg.js.map} +1 -1
- package/dist/{admin-linked-table-row-BsaUruCN.js → admin-linked-table-row-5vFb6rXY.js} +4 -4
- package/dist/{admin-linked-table-row-BsaUruCN.js.map → admin-linked-table-row-5vFb6rXY.js.map} +1 -1
- package/dist/{admin-metering-COFcSPQy.js → admin-metering-BksTFRRP.js} +14 -14
- package/dist/{admin-metering-COFcSPQy.js.map → admin-metering-BksTFRRP.js.map} +1 -1
- package/dist/{admin-ops-B3mcr76u.js → admin-ops-Ch2-BmUp.js} +11 -11
- package/dist/{admin-ops-B3mcr76u.js.map → admin-ops-Ch2-BmUp.js.map} +1 -1
- package/dist/{admin-orders-dxC99Idl.js → admin-orders-8XzHf7b-.js} +8 -8
- package/dist/{admin-orders-dxC99Idl.js.map → admin-orders-8XzHf7b-.js.map} +1 -1
- package/dist/{admin-payments-Bs7HSfP0.js → admin-payments-pNLNIU0X.js} +9 -9
- package/dist/{admin-payments-Bs7HSfP0.js.map → admin-payments-pNLNIU0X.js.map} +1 -1
- package/dist/{admin-price-detail-DRquxpA9.js → admin-price-detail-BeGDPxKX.js} +11 -11
- package/dist/admin-price-detail-BeGDPxKX.js.map +1 -0
- package/dist/{admin-price-wizard-CI7K-2Nz.js → admin-price-wizard-ferZSTfO.js} +7 -7
- package/dist/{admin-price-wizard-CI7K-2Nz.js.map → admin-price-wizard-ferZSTfO.js.map} +1 -1
- package/dist/{admin-range-picker-Dr2M1EZr.js → admin-range-picker-DaIvC1oC.js} +5 -5
- package/dist/{admin-range-picker-Dr2M1EZr.js.map → admin-range-picker-DaIvC1oC.js.map} +1 -1
- package/dist/{admin-reports-CywKLiSA.js → admin-reports-CA-cnNur.js} +8 -8
- package/dist/{admin-reports-CywKLiSA.js.map → admin-reports-CA-cnNur.js.map} +1 -1
- package/dist/{admin-select-DBgprVW6.js → admin-select-CUXvh6j1.js} +2 -2
- package/dist/{admin-select-DBgprVW6.js.map → admin-select-CUXvh6j1.js.map} +1 -1
- package/dist/{admin-settings-Bmoy95uO.js → admin-settings-C6eWFkDn.js} +16 -16
- package/dist/{admin-settings-Bmoy95uO.js.map → admin-settings-C6eWFkDn.js.map} +1 -1
- package/dist/{admin-skeleton-DsM7crYi.js → admin-skeleton-DEY3Q8Dg.js} +2 -2
- package/dist/{admin-skeleton-DsM7crYi.js.map → admin-skeleton-DEY3Q8Dg.js.map} +1 -1
- package/dist/{admin-status-badge-BFPgo71d.js → admin-status-badge-CwqIU8tK.js} +2 -2
- package/dist/{admin-status-badge-BFPgo71d.js.map → admin-status-badge-CwqIU8tK.js.map} +1 -1
- package/dist/{admin-subscriptions-CLYc_HEV.js → admin-subscriptions-lJG_EzMe.js} +9 -9
- package/dist/{admin-subscriptions-CLYc_HEV.js.map → admin-subscriptions-lJG_EzMe.js.map} +1 -1
- package/dist/{admin-switch-BJUxLCsa.js → admin-switch-S4g_ppaU.js} +2 -2
- package/dist/{admin-switch-BJUxLCsa.js.map → admin-switch-S4g_ppaU.js.map} +1 -1
- package/dist/{admin-table-CH9TrXJf.js → admin-table-CWhiCb9d.js} +2 -2
- package/dist/{admin-table-CH9TrXJf.js.map → admin-table-CWhiCb9d.js.map} +1 -1
- package/dist/{admin-tabs-528FJMjt.js → admin-tabs-Cjm5a6UJ.js} +2 -2
- package/dist/{admin-tabs-528FJMjt.js.map → admin-tabs-Cjm5a6UJ.js.map} +1 -1
- package/dist/{admin-textarea-DEz38RaI.js → admin-textarea-DK1Fq31x.js} +2 -2
- package/dist/{admin-textarea-DEz38RaI.js.map → admin-textarea-DK1Fq31x.js.map} +1 -1
- package/dist/{admin-typed-confirm-dialog-DU7m9-O7.js → admin-typed-confirm-dialog-BloZvFPA.js} +6 -6
- package/dist/{admin-typed-confirm-dialog-DU7m9-O7.js.map → admin-typed-confirm-dialog-BloZvFPA.js.map} +1 -1
- package/dist/{admin-utils-BK4Vh1o_.js → admin-utils-DnVY5fYd.js} +3 -3
- package/dist/admin-utils-DnVY5fYd.js.map +1 -0
- package/dist/{admin-widget-viz-Da48c-Zf.js → admin-widget-viz-RCkxUspL.js} +8 -8
- package/dist/{admin-widget-viz-Da48c-Zf.js.map → admin-widget-viz-RCkxUspL.js.map} +1 -1
- package/dist/admin.js +31 -31
- package/dist/admin.js.map +1 -1
- package/dist/appearance.d.ts +7 -7
- package/dist/buy-button.d.ts +12 -18
- package/dist/cart.d.ts +4 -4
- package/dist/client/client.d.ts +12 -20
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/routes.d.ts +10 -24
- package/dist/client/generated/wire.d.ts +75 -37
- package/dist/client/index.d.ts +1 -1
- package/dist/client/types.d.ts +17 -18
- package/dist/{client-DoRYitD3.js → client-HWr09qpX.js} +216 -233
- package/dist/client-HWr09qpX.js.map +1 -0
- package/dist/client.js +1 -1
- package/dist/embedded-payment.d.ts +25 -0
- package/dist/{hooks-DCSelDIZ.js → hooks-D9MR20BY.js} +7 -20
- package/dist/hooks-D9MR20BY.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +284 -272
- package/dist/index.js.map +1 -1
- package/dist/locales/de.js +1 -1
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.d.ts +1 -1
- package/dist/locales/en.js +1 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +1 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +1 -1
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +1 -1
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +1 -1
- package/dist/locales/zh.js.map +1 -1
- package/dist/modal.d.ts +12 -3
- package/dist/{order-checkout.d.ts → order-payment.d.ts} +4 -4
- package/dist/product-list.d.ts +10 -16
- package/dist/psp.d.ts +2 -2
- package/dist/react/hooks.d.ts +2 -15
- package/dist/react/index.d.ts +1 -1
- package/dist/react/provider.d.ts +3 -3
- package/dist/react.js +2 -2
- package/dist/save-payment-method.d.ts +2 -2
- package/dist/scope-context.d.ts +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/tokenized-card-form.d.ts +2 -2
- package/docs/payment-form-contract.md +3 -3
- package/package.json +2 -2
- package/dist/admin-price-detail-DRquxpA9.js.map +0 -1
- package/dist/admin-utils-BK4Vh1o_.js.map +0 -1
- package/dist/client-DoRYitD3.js.map +0 -1
- package/dist/embedded-checkout.d.ts +0 -22
- package/dist/hooks-DCSelDIZ.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## An order and its pay URL
|
|
4
|
+
|
|
5
|
+
- Breaking: "checkout" is gone. `EmbeddedCheckout` is `EmbeddedPayment`,
|
|
6
|
+
`OrderCheckout` is `OrderPayment` (with `EmbeddedPaymentProps`,
|
|
7
|
+
`EmbeddedPaymentCompletion`, `OrderPaymentProps`), and
|
|
8
|
+
`CHECKOUT_COMPLETE_MESSAGE` / `CHECKOUT_RESIZE_MESSAGE` are
|
|
9
|
+
`PAYMENT_COMPLETE_MESSAGE` / `PAYMENT_RESIZE_MESSAGE`, whose types are
|
|
10
|
+
`openrails.payment.complete` and `openrails.payment.resize`.
|
|
11
|
+
- Breaking: `createOrder({ payUrl: { embedded: true } })` replaces
|
|
12
|
+
`checkout: { ui_mode: "embedded" }`. The order answers `pay_url`,
|
|
13
|
+
`pay_url_expires_at`, `embedded`, `success_url`, `cancel_url` and
|
|
14
|
+
`saved_payment_methods` in place of `order.checkout`. The pay URL is
|
|
15
|
+
`/pay/<order>#<secret>` on the payment origin.
|
|
16
|
+
- Breaking: `CheckoutAppearance`, `CheckoutTheme` and `CheckoutVariables` are
|
|
17
|
+
`BillingAppearance`, `BillingTheme` and `BillingVariables`; `checkoutPsps`
|
|
18
|
+
is `routedPsps`, reading a PSP's `routed`.
|
|
19
|
+
|
|
20
|
+
## Hosts sell the products their pages carry
|
|
21
|
+
|
|
22
|
+
- Breaking: the browser never reads the catalog. `listProducts`, `useProducts`,
|
|
23
|
+
`ProductListOptions` and `ProductsState` are removed with OpenRails' public
|
|
24
|
+
`GET /products`; your server reads the catalog with the Go client and puts the
|
|
25
|
+
products in its page (`billing.BuyerPrices`).
|
|
26
|
+
- Breaking: `<ProductList products>` takes the host's products (no `merchant`
|
|
27
|
+
or `keys`); `<BuyButton price>` takes one of their prices (no `merchant`,
|
|
28
|
+
`product` or price key). `Purchase` is folded into `BuyButton`.
|
|
29
|
+
- `createOrder({ checkout: { ui_mode: "embedded" } })` creates the order with
|
|
30
|
+
its embedded checkout in one call: `order.checkout.url` on the checkout host,
|
|
31
|
+
as long as the order is open, returning nowhere (`success_url` null), for the
|
|
32
|
+
merchant's own signed-in person. Without `payment` it
|
|
33
|
+
answers the customer's open order of the same lines when there is one (with
|
|
34
|
+
a fresh URL); `idempotencyKey` is needed only with `payment`.
|
|
35
|
+
- On a site the merchant registered to frame its checkout, `BuyButton` creates
|
|
36
|
+
the order that way and frames it (`<EmbeddedCheckout>`); elsewhere it pays on
|
|
37
|
+
the page as before. It stores nothing and sends no key: a reload or a
|
|
38
|
+
reopened dialog answers the same open order.
|
|
39
|
+
|
|
3
40
|
## Entitlements read
|
|
4
41
|
|
|
5
42
|
- `getEntitlements()` lists the entitlement keys the customer holds
|
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# @openrails/billing-ui
|
|
2
2
|
|
|
3
|
-
Embeddable OpenRails billing UI:
|
|
3
|
+
Embeddable OpenRails billing UI: purchase, customer account billing, and staff
|
|
4
4
|
administration inside the host's application.
|
|
5
5
|
|
|
6
6
|
| Import | Contents |
|
|
7
7
|
| --------------------------------- | ---------------------------------------------------------------------------------- |
|
|
8
8
|
| `@openrails/billing-ui/client` | Framework-free typed client for `/billing/v1/me/*` and the catalog, `BillingError` |
|
|
9
9
|
| `@openrails/billing-ui/react` | `BillingProvider` and headless hooks, without styles |
|
|
10
|
-
| `@openrails/billing-ui` | `BillingProvider`, styled
|
|
10
|
+
| `@openrails/billing-ui` | `BillingProvider`, styled purchase and account components, i18n |
|
|
11
11
|
| `@openrails/billing-ui/locales/*` | `en de es ja ko zh` message bundles |
|
|
12
12
|
| `@openrails/billing-ui/admin` | `BillingAdmin`, `BillingCustomerSummary`, access and confirmation helpers |
|
|
13
13
|
| `@openrails/billing-ui/admin.css` | Scoped staff administration styles |
|
|
14
14
|
|
|
15
|
-
The
|
|
16
|
-
and `<
|
|
15
|
+
The purchase owns the browser payment flow, behind `<BuyButton>`, `<ProductList>`
|
|
16
|
+
and `<OrderPayment>`: the signed-in customer's order, read and paid with
|
|
17
17
|
their own credential. Card data is tokenized in the PSP's own fields
|
|
18
18
|
(Collect.js, Stripe Elements) and never enters the host application.
|
|
19
19
|
|
|
@@ -64,33 +64,41 @@ const billing = createBillingClient({
|
|
|
64
64
|
})
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
The browser never reads the catalog (Stripe's and Paddle's model): your
|
|
68
|
+
server reads the products it sells with the Go `Client.ListProducts` (by key,
|
|
69
|
+
or those granting an entitlement) and puts them in its own page's response,
|
|
70
|
+
their prices as a buyer sees them (`billing.BuyerPrices`). `<BuyButton price>`
|
|
71
|
+
buys one of those prices, `<ProductList products>` sells those products (a
|
|
72
|
+
course, its bundle and the membership that also unlocks it): a `BuyButton` per
|
|
73
|
+
price ("$4.99", "Rent for 3 days, $1.99", "$10.00 every 30 days").
|
|
74
|
+
|
|
75
|
+
The purchase is theirs from start to payment: a button creates the customer's
|
|
76
|
+
order (`POST /me/orders`) and pays it in a dialog. On a page of a site the
|
|
77
|
+
merchant registered to frame its pay URLs (`merchant.embed_origins` in
|
|
78
|
+
`GET /me/config`), it creates the order with its embedded pay URL in the same
|
|
79
|
+
call (`createOrder({ lines, payUrl: { embedded: true } })`) and frames
|
|
80
|
+
`order.pay_url` from the payment origin (`<EmbeddedPayment>`); anywhere
|
|
81
|
+
else it pays on the page (`<OrderPayment>`). The embedded pay URL returns
|
|
82
|
+
nowhere: the frame says it is paid and tells the page (`onPaid`), and a
|
|
83
|
+
redirect PSP comes back inside it. Nothing is stored: OpenRails answers the
|
|
84
|
+
customer's open order of the same lines, so a second click, a reopened dialog
|
|
85
|
+
or a reload pays the same order (with a fresh URL), and a paid or expired one
|
|
86
|
+
is bought again as a new order. Signing in is the
|
|
87
|
+
host's: with `signedIn={false}`, or when OpenRails answers 401, they call
|
|
88
|
+
`onSignInRequired` instead. `onPaid` receives the completed order; it is a
|
|
89
|
+
hint, so confirm access from your own API (your gate) before granting
|
|
90
|
+
anything.
|
|
80
91
|
|
|
81
92
|
```tsx
|
|
82
93
|
<BuyButton
|
|
83
|
-
|
|
84
|
-
product="course-101"
|
|
85
|
-
price="rent" // labelled from the catalog unless you pass label
|
|
94
|
+
price={course.prices[0]} // from your server's page response
|
|
86
95
|
signedIn={signedIn}
|
|
87
96
|
onSignInRequired={() => openSignIn()}
|
|
88
97
|
onPaid={() => navigate("/courses/css-101")} // your gate now admits them
|
|
89
98
|
/>
|
|
90
99
|
|
|
91
100
|
<ProductList
|
|
92
|
-
|
|
93
|
-
keys={["course-101", "course-bundle", "channel-membership"]} // from your server, or products={...} from its Client.ListProducts
|
|
101
|
+
products={products} // from your server's page response
|
|
94
102
|
signedIn={signedIn}
|
|
95
103
|
onSignInRequired={() => openSignIn()}
|
|
96
104
|
onPaid={() => navigate("/courses/css-101")}
|
|
@@ -102,18 +110,18 @@ must be on one of your app's return origins.
|
|
|
102
110
|
|
|
103
111
|
For prepaid credits, a fixed pack is another product/price. A
|
|
104
112
|
`customer_amount` price takes the buyer's `amount`: collect it on your product
|
|
105
|
-
page, and the
|
|
113
|
+
page, and the purchase charges exactly that:
|
|
106
114
|
|
|
107
115
|
```tsx
|
|
108
116
|
import { decimalToAmount } from "@openrails/billing-ui/client"
|
|
109
117
|
|
|
110
|
-
// `depositPrice` is in a product
|
|
118
|
+
// `depositPrice` is in a product your server sent; `currency` from getConfig().currencies.
|
|
111
119
|
// `enteredAmount` is the text from an <input inputMode="decimal">, e.g. "100".
|
|
112
120
|
const amount = decimalToAmount(enteredAmount, currency.decimals)
|
|
113
121
|
const bounds = depositPrice.customer_amount
|
|
114
122
|
const valid = amount && bounds && BigInt(amount) >= BigInt(bounds.min_amount) && BigInt(amount) <= BigInt(bounds.max_amount)
|
|
115
123
|
|
|
116
|
-
<BuyButton
|
|
124
|
+
<BuyButton price={depositPrice} amount={valid ? amount : undefined} label="Add credits" {...handlers} />
|
|
117
125
|
```
|
|
118
126
|
|
|
119
127
|
OpenRails validates the bounds and whole currency minor units before accepting
|
|
@@ -132,7 +140,7 @@ A server that decides what its customer buys creates the order with the Go
|
|
|
132
140
|
customer's browser, which pays it signed in:
|
|
133
141
|
|
|
134
142
|
```tsx
|
|
135
|
-
<
|
|
143
|
+
<OrderPayment orderId={orderId} returnUrl={returnUrl} onSettled={(order) => refetchAccess(order)} />
|
|
136
144
|
```
|
|
137
145
|
|
|
138
146
|
`onSettled` follows a complete order, or one processing on an asynchronous
|
|
@@ -205,15 +213,13 @@ host content and links. The customer imports above do not load admin code or
|
|
|
205
213
|
styles. See the [BillingAdmin integration guide](https://github.com/open-rails/openrails/blob/master/docs/billing-admin.md)
|
|
206
214
|
for merchant selection, permissions, localization, and standalone console setup.
|
|
207
215
|
|
|
208
|
-
##
|
|
216
|
+
## Configuration and plan changes
|
|
209
217
|
|
|
210
|
-
The client also reads the
|
|
211
|
-
|
|
212
|
-
no bearer.
|
|
218
|
+
The client also reads the configuration and changes a subscription's plan.
|
|
219
|
+
`GET /config` is a public route: the client sends it no bearer.
|
|
213
220
|
|
|
214
221
|
| Call | Route |
|
|
215
222
|
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
216
|
-
| `listProducts({ merchant, keys })`: the products `merchant` (its id) has on sale named by `keys` (1 to 100 product keys), each with its prices, in one page; `useProducts` reads the same | `GET /products` |
|
|
217
223
|
| `getConfig()` (capabilities, `currencies`, `captcha`; `client.currencies` is the pinned registry) | `GET /config` |
|
|
218
224
|
| `getCustomerConfig()` (the customer's merchant: `payment` with PSPs, `solana.network` and tokens, and `merchant`, its name) | `GET /me/config` |
|
|
219
225
|
| `previewSubscriptionChange(id, { priceId?, quantity? })` | `POST /me/subscriptions/{id}/change/preview` |
|
|
@@ -255,14 +261,14 @@ provider:
|
|
|
255
261
|
|
|
256
262
|
- An order's `payment_options` are exactly the armed PSPs whose rail can make
|
|
257
263
|
this sale (Solana for one-time lines when it is configured, never CCBill),
|
|
258
|
-
each with what it `accepts`. `
|
|
264
|
+
each with what it `accepts`. `OrderPayment` renders one panel: the
|
|
259
265
|
customer's saved cards on them, newest first, an inline new card and one Pay
|
|
260
266
|
button. No provider chooser with one rail.
|
|
261
267
|
- A new card is charged and saved in one pay; an `authenticate` next action
|
|
262
268
|
runs 3-D Secure in the page, then `confirm`. A decline stays on the panel
|
|
263
269
|
with its message, so the buyer can pick another card under a new
|
|
264
270
|
idempotency key.
|
|
265
|
-
- Only PSPs with `
|
|
271
|
+
- Only PSPs with `routed !== false` (`routedPsps`) take new cards; others
|
|
266
272
|
stay listed so existing cards and subscriptions keep working.
|
|
267
273
|
- `<SavePaymentMethod psp={psp} onSaved={(id) => ...} />` saves a card in the
|
|
268
274
|
page (needs `BillingProvider`); `canSavePaymentMethod(psp)` filters PSPs
|
|
@@ -278,8 +284,7 @@ provider:
|
|
|
278
284
|
subscription row; `useBillingRefresh()` refetches after host-side changes.
|
|
279
285
|
- Hooks: `useSubscriptions` (`cancel`, `resume`, `setPaymentMethod`,
|
|
280
286
|
`changeSubscription`, per-row `pending`, `nextCursor`), `usePaymentMethods` (`add`,
|
|
281
|
-
`remove`, `setDefault`), `usePayments` (cursor pages)
|
|
282
|
-
catalog lookup by product key).
|
|
287
|
+
`remove`, `setDefault`), `usePayments` (cursor pages).
|
|
283
288
|
Actions resolve to `null` or a `BillingError`; they never throw.
|
|
284
289
|
`changeSubscription` resolves to the `SubscriptionChange` instead of `null`. Cancel, resume
|
|
285
290
|
and the card change answer the subscription, which replaces the row.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { SendSolanaTransaction } from '../client/client';
|
|
3
3
|
import { SubscriptionsPanelProps } from './subscriptions-panel';
|
|
4
4
|
export interface AccountBillingProps {
|
|
@@ -13,7 +13,7 @@ export interface AccountBillingProps {
|
|
|
13
13
|
plansHref?: string;
|
|
14
14
|
renderSubscriptionFooter?: SubscriptionsPanelProps["renderSubscriptionFooter"];
|
|
15
15
|
historyPageSize?: number;
|
|
16
|
-
appearance?:
|
|
16
|
+
appearance?: BillingAppearance;
|
|
17
17
|
className?: string;
|
|
18
18
|
}
|
|
19
19
|
/** Subscriptions, payment methods and history in one column. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { BillingError } from '../client/errors';
|
|
3
3
|
import { SubscriptionAction } from '../react/hooks';
|
|
4
4
|
import * as React from "react";
|
|
@@ -13,6 +13,6 @@ export interface CancelSubscriptionDialogProps {
|
|
|
13
13
|
pending?: SubscriptionAction;
|
|
14
14
|
/** Resolves null on success; the dialog then closes. */
|
|
15
15
|
onConfirm: (reason: string) => Promise<BillingError | null>;
|
|
16
|
-
appearance?:
|
|
16
|
+
appearance?: BillingAppearance;
|
|
17
17
|
}
|
|
18
18
|
export declare function CancelSubscriptionDialog({ open, onOpenChange, name, onChain, pending, onConfirm, appearance, }: CancelSubscriptionDialogProps): React.JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { BillingError } from '../client/errors';
|
|
3
3
|
import { Subscription } from '../client/types';
|
|
4
4
|
import * as React from "react";
|
|
@@ -12,6 +12,6 @@ export interface ChangeCardDialogProps {
|
|
|
12
12
|
* null on success; the dialog then closes.
|
|
13
13
|
*/
|
|
14
14
|
onConfirm: (paymentMethodId: string | null) => Promise<BillingError | null>;
|
|
15
|
-
appearance?:
|
|
15
|
+
appearance?: BillingAppearance;
|
|
16
16
|
}
|
|
17
17
|
export declare function ChangeCardDialog({ subscription, name, onOpenChange, pending, onConfirm, appearance, }: ChangeCardDialogProps): React.JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { PaymentsOptions } from '../react/hooks';
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
export interface PaymentHistoryProps extends PaymentsOptions {
|
|
5
|
-
appearance?:
|
|
5
|
+
appearance?: BillingAppearance;
|
|
6
6
|
className?: string;
|
|
7
7
|
}
|
|
8
8
|
export declare function PaymentHistory({ appearance, className, ...options }: PaymentHistoryProps): React.JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
export interface PaymentMethodsPanelProps {
|
|
4
4
|
/**
|
|
@@ -8,7 +8,7 @@ export interface PaymentMethodsPanelProps {
|
|
|
8
8
|
defaultCurrency?: string;
|
|
9
9
|
/** Billing country to preselect when adding a card. */
|
|
10
10
|
defaultCountry?: string;
|
|
11
|
-
appearance?:
|
|
11
|
+
appearance?: BillingAppearance;
|
|
12
12
|
className?: string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { BillingError } from '../client/errors';
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
export interface SectionProps {
|
|
5
5
|
title: string;
|
|
6
6
|
description?: string;
|
|
7
7
|
action?: React.ReactNode;
|
|
8
|
-
appearance?:
|
|
8
|
+
appearance?: BillingAppearance;
|
|
9
9
|
className?: string;
|
|
10
10
|
children?: React.ReactNode;
|
|
11
11
|
"data-testid"?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BillingAppearance } from '../appearance';
|
|
2
2
|
import { SendSolanaTransaction } from '../client/client';
|
|
3
3
|
import { Subscription } from '../client/types';
|
|
4
4
|
import { SubscriptionsOptions } from '../react/hooks';
|
|
@@ -13,7 +13,7 @@ export interface SubscriptionsPanelProps extends SubscriptionsOptions {
|
|
|
13
13
|
plansHref?: string;
|
|
14
14
|
/** Host content under a row, e.g. a plan-change control. */
|
|
15
15
|
renderSubscriptionFooter?: (subscription: Subscription) => React.ReactNode;
|
|
16
|
-
appearance?:
|
|
16
|
+
appearance?: BillingAppearance;
|
|
17
17
|
className?: string;
|
|
18
18
|
}
|
|
19
19
|
export declare function SubscriptionsPanel({ sendSolanaTransaction, plansHref, renderSubscriptionFooter, appearance, className, ...options }: SubscriptionsPanelProps): React.JSX.Element;
|
package/dist/admin/context.d.ts
CHANGED
|
@@ -428,7 +428,7 @@ export declare function createAdminServices(options: AdminClientOptions): {
|
|
|
428
428
|
limit: number;
|
|
429
429
|
cursor: string | undefined;
|
|
430
430
|
})[], import('./lib/api/credit-types').ListPage<import('./lib/api/types').Finding>, Error>;
|
|
431
|
-
|
|
431
|
+
pspRouting: (priceId: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./lib/api/types').PSPRoutingPreview, Error, import('./lib/api/types').PSPRoutingPreview, string[]>, "queryFn"> & {
|
|
432
432
|
queryFn?: import('@tanstack/react-query').QueryFunction<import('./lib/api/types').PSPRoutingPreview, string[], never> | undefined;
|
|
433
433
|
} & import('@tanstack/react-query').QueryKeyWithDataTag<string[], import('./lib/api/types').PSPRoutingPreview, Error>;
|
|
434
434
|
usageMeters: (limit?: number, cursor?: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./lib/api/credit-types').ListPage<import('../client/generated/wire').Meter>, Error, import('./lib/api/credit-types').ListPage<import('../client/generated/wire').Meter>, (string | {
|
|
@@ -1028,7 +1028,7 @@ export declare const useAdminServices: () => {
|
|
|
1028
1028
|
limit: number;
|
|
1029
1029
|
cursor: string | undefined;
|
|
1030
1030
|
})[], import('./lib/api/credit-types').ListPage<import('./lib/api/types').Finding>, Error>;
|
|
1031
|
-
|
|
1031
|
+
pspRouting: (priceId: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./lib/api/types').PSPRoutingPreview, Error, import('./lib/api/types').PSPRoutingPreview, string[]>, "queryFn"> & {
|
|
1032
1032
|
queryFn?: import('@tanstack/react-query').QueryFunction<import('./lib/api/types').PSPRoutingPreview, string[], never> | undefined;
|
|
1033
1033
|
} & import('@tanstack/react-query').QueryKeyWithDataTag<string[], import('./lib/api/types').PSPRoutingPreview, Error>;
|
|
1034
1034
|
usageMeters: (limit?: number, cursor?: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./lib/api/credit-types').ListPage<import('../client/generated/wire').Meter>, Error, import('./lib/api/credit-types').ListPage<import('../client/generated/wire').Meter>, (string | {
|
|
@@ -301,7 +301,7 @@ export declare function createQueries(client: AdminClient, api: AdminAPI): {
|
|
|
301
301
|
limit: number;
|
|
302
302
|
cursor: string | undefined;
|
|
303
303
|
})[], ListPage<import('./api/types').Finding>, Error>;
|
|
304
|
-
|
|
304
|
+
pspRouting: (priceId: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<import('./api/types').PSPRoutingPreview, Error, import('./api/types').PSPRoutingPreview, string[]>, "queryFn"> & {
|
|
305
305
|
queryFn?: import('@tanstack/react-query').QueryFunction<import('./api/types').PSPRoutingPreview, string[], never> | undefined;
|
|
306
306
|
} & import('@tanstack/react-query').QueryKeyWithDataTag<string[], import('./api/types').PSPRoutingPreview, Error>;
|
|
307
307
|
usageMeters: (limit?: number, cursor?: string) => import('@tanstack/react-query').OmitKeyof<import('@tanstack/react-query').UseQueryOptions<ListPage<import('../../client/generated/wire').Meter>, Error, ListPage<import('../../client/generated/wire').Meter>, (string | {
|
package/dist/admin/messages.d.ts
CHANGED
|
@@ -323,11 +323,11 @@ export declare const billingAdminMessages: {
|
|
|
323
323
|
readonly "New batch": "New batch";
|
|
324
324
|
readonly "New cards by AVS result": "New cards by AVS result";
|
|
325
325
|
readonly "New cards by CVV result": "New cards by CVV result";
|
|
326
|
-
readonly "New
|
|
326
|
+
readonly "New purchase on this rail is refused until another PSP is armed. Existing subscriptions, refunds and webhooks keep using this one.": "New purchase on this rail is refused until another PSP is armed. Existing subscriptions, refunds and webhooks keep using this one.";
|
|
327
327
|
readonly "New merchant": "New merchant";
|
|
328
328
|
readonly "New plan": "New plan";
|
|
329
329
|
readonly "New price": "New price";
|
|
330
|
-
readonly "New-card
|
|
330
|
+
readonly "New-card purchase failure rate": "New-card purchase failure rate";
|
|
331
331
|
readonly "New-card decline rate": "New-card decline rate";
|
|
332
332
|
readonly "New-card decline rate by week": "New-card decline rate by week";
|
|
333
333
|
readonly Next: "Next";
|
|
@@ -619,7 +619,7 @@ export declare const billingAdminMessages: {
|
|
|
619
619
|
readonly "Webhook URL": "Webhook URL";
|
|
620
620
|
readonly Webhooks: "Webhooks";
|
|
621
621
|
readonly "What the customer asked for": "What the customer asked for";
|
|
622
|
-
readonly "Which provider would take the money if someone bought this right now, and why the others were passed over. This asks the same question a real
|
|
622
|
+
readonly "Which provider would take the money if someone bought this right now, and why the others were passed over. This asks the same question a real purchase asks, without starting one.": "Which provider would take the money if someone bought this right now, and why the others were passed over. This asks the same question a real purchase asks, without starting one.";
|
|
623
623
|
readonly "Which providers this price has been sent to, and whether their copy still matches yours. Publishing the catalog is what sends it; this page only reports. Verify asks each provider what it currently holds, and changes nothing.": "Which providers this price has been sent to, and whether their copy still matches yours. Publishing the catalog is what sends it; this page only reports. Verify asks each provider what it currently holds, and changes nothing.";
|
|
624
624
|
readonly Why: "Why";
|
|
625
625
|
readonly "Why it was granted": "Why it was granted";
|
|
@@ -5,6 +5,6 @@ export declare function PSPLinksCard({ price, verifying, verified, onVerify, }:
|
|
|
5
5
|
verified: boolean;
|
|
6
6
|
onVerify: () => void;
|
|
7
7
|
}): import("react").JSX.Element;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function PSPReadinessCard({ price }: {
|
|
9
9
|
price: Price;
|
|
10
10
|
}): import("react").JSX.Element;
|
package/dist/admin/theme.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function useAdminTheme(theme?:
|
|
1
|
+
import { BillingTheme } from '../appearance';
|
|
2
|
+
export declare function useAdminTheme(theme?: BillingTheme): "inherit" | "light" | "dark";
|
package/dist/admin/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
3
|
+
import { BillingAppearance } from '../appearance';
|
|
4
4
|
import { Customer } from '../client/generated/wire';
|
|
5
5
|
/** The host's authenticated transport. Tokens remain with the host. */
|
|
6
6
|
export interface BillingAdminAuth {
|
|
@@ -47,7 +47,7 @@ export interface BillingAdminProps {
|
|
|
47
47
|
userHref?: (id: string) => string;
|
|
48
48
|
newMerchantHref?: string;
|
|
49
49
|
emptyState?: ReactNode;
|
|
50
|
-
appearance?:
|
|
50
|
+
appearance?: BillingAppearance;
|
|
51
51
|
className?: string;
|
|
52
52
|
style?: CSSProperties;
|
|
53
53
|
queryClient?: QueryClient;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { E as e, c as t, l as n, p as r, r as i, s as a, v as o, w as s, x as c, y as l } from "./admin-utils-
|
|
2
|
-
import { t as u } from "./admin-button-
|
|
1
|
+
import { E as e, c as t, l as n, p as r, r as i, s as a, v as o, w as s, x as c, y as l } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as u } from "./admin-button-Oip73Plq.js";
|
|
3
3
|
import { i as d, o as f, s as p, u as m } from "./admin-format-DoohJ7Fg.js";
|
|
4
|
-
import { i as h, n as g } from "./admin-dom-
|
|
5
|
-
import { t as _ } from "./admin-status-badge-
|
|
6
|
-
import { a as v, o as y, r as b, t as x } from "./admin-card-
|
|
7
|
-
import { t as S } from "./admin-fact-card-
|
|
8
|
-
import { t as C } from "./admin-data-table-
|
|
4
|
+
import { i as h, n as g } from "./admin-dom-lnNSQ7ke.js";
|
|
5
|
+
import { t as _ } from "./admin-status-badge-CwqIU8tK.js";
|
|
6
|
+
import { a as v, o as y, r as b, t as x } from "./admin-card-DGbi6ZHZ.js";
|
|
7
|
+
import { t as S } from "./admin-fact-card-D6mZgxpN.js";
|
|
8
|
+
import { t as C } from "./admin-data-table-CgeWv__T.js";
|
|
9
9
|
import { useQuery as w } from "@tanstack/react-query";
|
|
10
10
|
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
11
11
|
import { HugeiconsIcon as D } from "@hugeicons/react";
|
|
@@ -416,4 +416,4 @@ function z() {
|
|
|
416
416
|
//#endregion
|
|
417
417
|
export { I as AttemptDetailPage, N as AttemptsPage, z as CycleDetailPage, R as CyclesPage };
|
|
418
418
|
|
|
419
|
-
//# sourceMappingURL=admin-attempts-
|
|
419
|
+
//# sourceMappingURL=admin-attempts-DxRHTODq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-attempts-lAoW-Urd.js","names":[],"sources":["../src/admin/pages/payments/attempts.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\n// Payments → Attempts and Renewals (#1117): the #1116 lists and details.\n// A list's filters are its URL's query parameters, as the API names them, so\n// the health page links straight into a filtered list.\nimport { HugeiconsIcon } from \"@hugeicons/react\"\nimport { ArrowLeft01Icon, Cancel01Icon } from \"@hugeicons/core-free-icons\"\nimport {\n Link,\n useNavigate,\n useParams,\n useSearchParams,\n} from \"#orck/admin/router\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nimport { CursorPager } from \"#orck/admin/components/cursor-pager\"\nimport { DataTable } from \"#orck/admin/components/data-table\"\nimport { Fact } from \"#orck/admin/components/fact-card\"\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n} from \"#orck/admin/components/ui/card\"\nimport {\n ATTEMPT_FILTERS,\n CYCLE_FILTERS,\n filtersFrom,\n type AttemptFilters,\n type CycleFilters,\n} from \"#orck/admin/lib/api/endpoints\"\nimport type { PaymentAttempt, Renewal } from \"#orck/client/generated/wire\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport {\n formatCard,\n formatDate,\n formatNativeAmount,\n shortId,\n} from \"#orck/admin/lib/format\"\n\nexport function Outcome({ category }: { category: string }) {\n return (\n <StatusBadge status={category === \"approved\" ? \"approved\" : \"declined\"} />\n )\n}\n\nconst attemptColumns: ColumnDef<PaymentAttempt, unknown>[] = [\n {\n header: \"Attempted\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.attempted_at)}\n </span>\n ),\n },\n { header: \"Kind\", cell: ({ row }) => row.original.kind },\n {\n header: \"Outcome\",\n cell: ({ row }) => <Outcome category={row.original.category} />,\n },\n {\n header: \"Reason\",\n cell: ({ row }) =>\n row.original.category === \"approved\" ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n <span>\n {row.original.reason || row.original.category}\n {row.original.response_code ? (\n <span className=\"ml-1 font-mono text-xs text-muted-foreground\">\n {row.original.response_code}\n </span>\n ) : null}\n </span>\n ),\n },\n { header: \"Owner\", cell: ({ row }) => row.original.owner },\n { header: \"Card\", cell: ({ row }) => formatCard(row.original.card) },\n {\n header: \"Amount\",\n cell: ({ row }) =>\n row.original.currency ? (\n <span className=\"tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n ),\n },\n { header: \"Rail\", cell: ({ row }) => row.original.rail },\n]\n\nfunction FilterChips({ keys }: { keys: readonly string[] }) {\n const [params, setParams] = useSearchParams()\n const active = keys.filter((k) => params.get(k))\n if (active.length === 0) return null\n const drop = (key?: string) => {\n const p = new URLSearchParams(params)\n for (const k of key ? [key] : active) p.delete(k)\n p.delete(\"cursor\")\n setParams(p)\n }\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n {active.map((k) => (\n <span\n key={k}\n className=\"inline-flex items-center gap-1 rounded-md bg-muted py-0.5 pr-1 pl-2\"\n >\n <span className=\"text-muted-foreground\">{k}</span>\n <span className=\"font-medium\">{params.get(k)}</span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-5\"\n aria-label={`Clear ${k}`}\n onClick={() => drop(k)}\n >\n <HugeiconsIcon icon={Cancel01Icon} className=\"size-3\" />\n </Button>\n </span>\n ))}\n <Button variant=\"ghost\" size=\"sm\" onClick={() => drop()}>\n <AdminMessage id={\"Clear all\"} />\n </Button>\n </div>\n )\n}\n\nexport function AttemptsPage() {\n const { adminQueries } = useAdminServices()\n\n const [params] = useSearchParams()\n const paging = useUrlCursor()\n const navigate = useNavigate()\n const filters: AttemptFilters = filtersFrom(params, ATTEMPT_FILTERS)\n const { data, isPending, isFetching } = useQuery(\n adminQueries.attempts(filters, paging.size, paging.cursor)\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Payment attempts\"} />\n </h1>\n <FilterChips keys={ATTEMPT_FILTERS} />\n <DataTable\n columns={attemptColumns}\n data={data?.data ?? []}\n loading={isPending}\n onRowClick={(row) => navigate(`/payments/attempts/${row.id}`)}\n emptyMessage=\"No attempts match.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </div>\n )\n}\n\nfunction Back() {\n const { text: adminText } = useAdminUI()\n\n const navigate = useNavigate()\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigate(-1)}\n aria-label={adminText(\"Back\")}\n >\n <HugeiconsIcon icon={ArrowLeft01Icon} className=\"size-4\" />\n </Button>\n )\n}\n\nfunction To({ to, children }: { to: string; children: string }) {\n return (\n <Link className=\"text-xs underline-offset-2 hover:underline\" to={to}>\n {children}\n </Link>\n )\n}\n\nexport function AttemptDetailPage() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const { id = \"\" } = useParams()\n const { data: a, isPending } = useQuery(adminQueries.attempt(id))\n if (isPending)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n )\n if (!a)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Attempt not found.\"} />\n </p>\n )\n const answer = [\n [\"Response\", [a.response_code, a.response_text].filter(Boolean).join(\" \")],\n [\"Issuer\", [a.issuer_code, a.issuer_text].filter(Boolean).join(\" \")],\n [\"AVS\", a.avs_result],\n [\"CVV\", a.cvv_result],\n [\"Action\", a.action],\n [\"Token\", a.token_type],\n [\"BIN\", a.card_bin],\n [\"Transaction\", a.transaction_id],\n [\"Observed via\", `${a.source} · ${a.observed_via}`],\n [\"Enriched\", a.enriched_at ? formatDate(a.enriched_at) : \"\"],\n ] as const\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <Back />\n <div>\n <h2 className=\"flex items-center gap-2 text-sm\">\n {a.id} <Outcome category={a.category} />\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {a.kind} · {a.owner} · {a.rail} · {formatDate(a.attempted_at)}\n </p>\n </div>\n </div>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Fact label={adminText(\"Outcome\")}>\n {a.category === \"approved\"\n ? \"approved\"\n : `${a.category}${a.reason ? ` · ${a.reason}` : \"\"}`}\n </Fact>\n <Fact label={adminText(\"Amount\")}>\n {a.currency ? formatNativeAmount(a.amount, a.currency) : \"—\"}\n </Fact>\n <Fact label={adminText(\"Card\")}>\n {formatCard(a.card)} ({a.card_entry})\n </Fact>\n <Fact label={adminText(\"Customer\")}>\n <To to={`/customers/${a.customer_id}`}>\n {shortId(a.customer_id, 16)}\n </To>\n </Fact>\n <Fact label={adminText(\"Subscription\")}>\n {a.subscription_id ? (\n <To to={`/subscriptions/${a.subscription_id}`}>\n {shortId(a.subscription_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Renewal\")}>\n {a.cycle_id ? (\n <To to={`/payments/cycles/${a.cycle_id}`}>\n {shortId(a.cycle_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Payment\")}>\n {a.payment_id ? (\n <To to={`/payments/${a.payment_id}`}>\n {shortId(a.payment_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Paying\")}>\n {a.order_id ? (\n <To to={`/orders/${a.order_id}`}>{shortId(a.order_id, 16)}</To>\n ) : (\n \"—\"\n )}\n </Fact>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"PSP answer\"} />\n </CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2\">\n {answer.map(([label, value]) => (\n <div key={label} className=\"flex gap-2\">\n <dt className=\"w-28 shrink-0 text-muted-foreground\">{label}</dt>\n <dd className=\"font-mono text-xs break-all\">{value || \"—\"}</dd>\n </div>\n ))}\n </dl>\n </CardContent>\n </Card>\n </div>\n )\n}\n\n// --- renewals ----------------------------------------------------------------------\n\nconst cycleColumns: ColumnDef<Renewal, unknown>[] = [\n {\n header: \"Due\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.due_at)}\n </span>\n ),\n },\n { header: \"Owner\", cell: ({ row }) => row.original.owner },\n {\n header: \"First outcome\",\n cell: ({ row }) =>\n row.original.miss_reason\n ? `missed · ${row.original.miss_reason}`\n : row.original.first_outcome,\n },\n {\n header: \"Outcome\",\n cell: ({ row }) => <StatusBadge status={row.original.outcome} />,\n },\n {\n header: \"Recovered by\",\n cell: ({ row }) => row.original.recovered_by || \"—\",\n },\n {\n header: \"Amount\",\n cell: ({ row }) => (\n <span className=\"tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ),\n },\n { header: \"Rail\", cell: ({ row }) => row.original.rail },\n]\n\nexport function CyclesPage() {\n const { adminQueries } = useAdminServices()\n\n const [params] = useSearchParams()\n const paging = useUrlCursor()\n const navigate = useNavigate()\n const filters: CycleFilters = filtersFrom(params, CYCLE_FILTERS)\n const { data, isPending, isFetching } = useQuery(\n adminQueries.cycles(filters, paging.size, paging.cursor)\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Renewals\"} />\n </h1>\n <FilterChips keys={CYCLE_FILTERS} />\n <DataTable\n columns={cycleColumns}\n data={data?.data ?? []}\n loading={isPending}\n onRowClick={(row) => navigate(`/payments/cycles/${row.id}`)}\n emptyMessage=\"No renewals match.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </div>\n )\n}\n\nexport function CycleDetailPage() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const { id = \"\" } = useParams()\n const navigate = useNavigate()\n const { data: c, isPending } = useQuery(adminQueries.cycle(id))\n if (isPending)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n )\n if (!c)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Renewal not found.\"} />\n </p>\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <Back />\n <div>\n <h2 className=\"flex items-center gap-2 text-sm\">\n {c.id} <StatusBadge status={c.outcome} />\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {c.owner} · {c.rail}\n <AdminMessage id={\" · due \"} />\n {formatDate(c.due_at)}\n </p>\n </div>\n </div>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Fact label={adminText(\"Amount\")}>\n {formatNativeAmount(c.amount, c.currency)}\n </Fact>\n <Fact label={adminText(\"First outcome\")}>\n {c.miss_reason ? `missed · ${c.miss_reason}` : c.first_outcome}\n </Fact>\n <Fact label={adminText(\"Collected\")}>\n {c.collected_at\n ? `${formatDate(c.collected_at)}${c.recovered_by ? ` · ${c.recovered_by}` : \"\"}`\n : \"—\"}\n </Fact>\n <Fact label={c.outcome === \"open\" ? \"Closes\" : \"Closed\"}>\n {formatDate(c.closes_at)}\n </Fact>\n <Fact label={adminText(\"Subscription\")}>\n <To to={`/subscriptions/${c.subscription_id}`}>\n {shortId(c.subscription_id, 16)}\n </To>\n </Fact>\n <Fact label={adminText(\"Customer\")}>\n <To to={`/customers/${c.customer_id}`}>\n {shortId(c.customer_id, 16)}\n </To>\n </Fact>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"Attempts\"} />\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={attemptColumns}\n data={c.attempts ?? []}\n onRowClick={(row) => navigate(`/payments/attempts/${row.id}`)}\n emptyMessage={\n c.miss_reason ? \"Never attempted.\" : \"No attempts yet.\"\n }\n />\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-attempts-DxRHTODq.js","names":[],"sources":["../src/admin/pages/payments/attempts.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\n// Payments → Attempts and Renewals (#1117): the #1116 lists and details.\n// A list's filters are its URL's query parameters, as the API names them, so\n// the health page links straight into a filtered list.\nimport { HugeiconsIcon } from \"@hugeicons/react\"\nimport { ArrowLeft01Icon, Cancel01Icon } from \"@hugeicons/core-free-icons\"\nimport {\n Link,\n useNavigate,\n useParams,\n useSearchParams,\n} from \"#orck/admin/router\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\n\nimport { CursorPager } from \"#orck/admin/components/cursor-pager\"\nimport { DataTable } from \"#orck/admin/components/data-table\"\nimport { Fact } from \"#orck/admin/components/fact-card\"\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n} from \"#orck/admin/components/ui/card\"\nimport {\n ATTEMPT_FILTERS,\n CYCLE_FILTERS,\n filtersFrom,\n type AttemptFilters,\n type CycleFilters,\n} from \"#orck/admin/lib/api/endpoints\"\nimport type { PaymentAttempt, Renewal } from \"#orck/client/generated/wire\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport {\n formatCard,\n formatDate,\n formatNativeAmount,\n shortId,\n} from \"#orck/admin/lib/format\"\n\nexport function Outcome({ category }: { category: string }) {\n return (\n <StatusBadge status={category === \"approved\" ? \"approved\" : \"declined\"} />\n )\n}\n\nconst attemptColumns: ColumnDef<PaymentAttempt, unknown>[] = [\n {\n header: \"Attempted\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.attempted_at)}\n </span>\n ),\n },\n { header: \"Kind\", cell: ({ row }) => row.original.kind },\n {\n header: \"Outcome\",\n cell: ({ row }) => <Outcome category={row.original.category} />,\n },\n {\n header: \"Reason\",\n cell: ({ row }) =>\n row.original.category === \"approved\" ? (\n <span className=\"text-muted-foreground\">—</span>\n ) : (\n <span>\n {row.original.reason || row.original.category}\n {row.original.response_code ? (\n <span className=\"ml-1 font-mono text-xs text-muted-foreground\">\n {row.original.response_code}\n </span>\n ) : null}\n </span>\n ),\n },\n { header: \"Owner\", cell: ({ row }) => row.original.owner },\n { header: \"Card\", cell: ({ row }) => formatCard(row.original.card) },\n {\n header: \"Amount\",\n cell: ({ row }) =>\n row.original.currency ? (\n <span className=\"tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n ),\n },\n { header: \"Rail\", cell: ({ row }) => row.original.rail },\n]\n\nfunction FilterChips({ keys }: { keys: readonly string[] }) {\n const [params, setParams] = useSearchParams()\n const active = keys.filter((k) => params.get(k))\n if (active.length === 0) return null\n const drop = (key?: string) => {\n const p = new URLSearchParams(params)\n for (const k of key ? [key] : active) p.delete(k)\n p.delete(\"cursor\")\n setParams(p)\n }\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n {active.map((k) => (\n <span\n key={k}\n className=\"inline-flex items-center gap-1 rounded-md bg-muted py-0.5 pr-1 pl-2\"\n >\n <span className=\"text-muted-foreground\">{k}</span>\n <span className=\"font-medium\">{params.get(k)}</span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-5\"\n aria-label={`Clear ${k}`}\n onClick={() => drop(k)}\n >\n <HugeiconsIcon icon={Cancel01Icon} className=\"size-3\" />\n </Button>\n </span>\n ))}\n <Button variant=\"ghost\" size=\"sm\" onClick={() => drop()}>\n <AdminMessage id={\"Clear all\"} />\n </Button>\n </div>\n )\n}\n\nexport function AttemptsPage() {\n const { adminQueries } = useAdminServices()\n\n const [params] = useSearchParams()\n const paging = useUrlCursor()\n const navigate = useNavigate()\n const filters: AttemptFilters = filtersFrom(params, ATTEMPT_FILTERS)\n const { data, isPending, isFetching } = useQuery(\n adminQueries.attempts(filters, paging.size, paging.cursor)\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Payment attempts\"} />\n </h1>\n <FilterChips keys={ATTEMPT_FILTERS} />\n <DataTable\n columns={attemptColumns}\n data={data?.data ?? []}\n loading={isPending}\n onRowClick={(row) => navigate(`/payments/attempts/${row.id}`)}\n emptyMessage=\"No attempts match.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </div>\n )\n}\n\nfunction Back() {\n const { text: adminText } = useAdminUI()\n\n const navigate = useNavigate()\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigate(-1)}\n aria-label={adminText(\"Back\")}\n >\n <HugeiconsIcon icon={ArrowLeft01Icon} className=\"size-4\" />\n </Button>\n )\n}\n\nfunction To({ to, children }: { to: string; children: string }) {\n return (\n <Link className=\"text-xs underline-offset-2 hover:underline\" to={to}>\n {children}\n </Link>\n )\n}\n\nexport function AttemptDetailPage() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const { id = \"\" } = useParams()\n const { data: a, isPending } = useQuery(adminQueries.attempt(id))\n if (isPending)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n )\n if (!a)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Attempt not found.\"} />\n </p>\n )\n const answer = [\n [\"Response\", [a.response_code, a.response_text].filter(Boolean).join(\" \")],\n [\"Issuer\", [a.issuer_code, a.issuer_text].filter(Boolean).join(\" \")],\n [\"AVS\", a.avs_result],\n [\"CVV\", a.cvv_result],\n [\"Action\", a.action],\n [\"Token\", a.token_type],\n [\"BIN\", a.card_bin],\n [\"Transaction\", a.transaction_id],\n [\"Observed via\", `${a.source} · ${a.observed_via}`],\n [\"Enriched\", a.enriched_at ? formatDate(a.enriched_at) : \"\"],\n ] as const\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <Back />\n <div>\n <h2 className=\"flex items-center gap-2 text-sm\">\n {a.id} <Outcome category={a.category} />\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {a.kind} · {a.owner} · {a.rail} · {formatDate(a.attempted_at)}\n </p>\n </div>\n </div>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Fact label={adminText(\"Outcome\")}>\n {a.category === \"approved\"\n ? \"approved\"\n : `${a.category}${a.reason ? ` · ${a.reason}` : \"\"}`}\n </Fact>\n <Fact label={adminText(\"Amount\")}>\n {a.currency ? formatNativeAmount(a.amount, a.currency) : \"—\"}\n </Fact>\n <Fact label={adminText(\"Card\")}>\n {formatCard(a.card)} ({a.card_entry})\n </Fact>\n <Fact label={adminText(\"Customer\")}>\n <To to={`/customers/${a.customer_id}`}>\n {shortId(a.customer_id, 16)}\n </To>\n </Fact>\n <Fact label={adminText(\"Subscription\")}>\n {a.subscription_id ? (\n <To to={`/subscriptions/${a.subscription_id}`}>\n {shortId(a.subscription_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Renewal\")}>\n {a.cycle_id ? (\n <To to={`/payments/cycles/${a.cycle_id}`}>\n {shortId(a.cycle_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Payment\")}>\n {a.payment_id ? (\n <To to={`/payments/${a.payment_id}`}>\n {shortId(a.payment_id, 16)}\n </To>\n ) : (\n \"—\"\n )}\n </Fact>\n <Fact label={adminText(\"Paying\")}>\n {a.order_id ? (\n <To to={`/orders/${a.order_id}`}>{shortId(a.order_id, 16)}</To>\n ) : (\n \"—\"\n )}\n </Fact>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"PSP answer\"} />\n </CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2\">\n {answer.map(([label, value]) => (\n <div key={label} className=\"flex gap-2\">\n <dt className=\"w-28 shrink-0 text-muted-foreground\">{label}</dt>\n <dd className=\"font-mono text-xs break-all\">{value || \"—\"}</dd>\n </div>\n ))}\n </dl>\n </CardContent>\n </Card>\n </div>\n )\n}\n\n// --- renewals ----------------------------------------------------------------------\n\nconst cycleColumns: ColumnDef<Renewal, unknown>[] = [\n {\n header: \"Due\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.due_at)}\n </span>\n ),\n },\n { header: \"Owner\", cell: ({ row }) => row.original.owner },\n {\n header: \"First outcome\",\n cell: ({ row }) =>\n row.original.miss_reason\n ? `missed · ${row.original.miss_reason}`\n : row.original.first_outcome,\n },\n {\n header: \"Outcome\",\n cell: ({ row }) => <StatusBadge status={row.original.outcome} />,\n },\n {\n header: \"Recovered by\",\n cell: ({ row }) => row.original.recovered_by || \"—\",\n },\n {\n header: \"Amount\",\n cell: ({ row }) => (\n <span className=\"tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ),\n },\n { header: \"Rail\", cell: ({ row }) => row.original.rail },\n]\n\nexport function CyclesPage() {\n const { adminQueries } = useAdminServices()\n\n const [params] = useSearchParams()\n const paging = useUrlCursor()\n const navigate = useNavigate()\n const filters: CycleFilters = filtersFrom(params, CYCLE_FILTERS)\n const { data, isPending, isFetching } = useQuery(\n adminQueries.cycles(filters, paging.size, paging.cursor)\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Renewals\"} />\n </h1>\n <FilterChips keys={CYCLE_FILTERS} />\n <DataTable\n columns={cycleColumns}\n data={data?.data ?? []}\n loading={isPending}\n onRowClick={(row) => navigate(`/payments/cycles/${row.id}`)}\n emptyMessage=\"No renewals match.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </div>\n )\n}\n\nexport function CycleDetailPage() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const { id = \"\" } = useParams()\n const navigate = useNavigate()\n const { data: c, isPending } = useQuery(adminQueries.cycle(id))\n if (isPending)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n )\n if (!c)\n return (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Renewal not found.\"} />\n </p>\n )\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <Back />\n <div>\n <h2 className=\"flex items-center gap-2 text-sm\">\n {c.id} <StatusBadge status={c.outcome} />\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {c.owner} · {c.rail}\n <AdminMessage id={\" · due \"} />\n {formatDate(c.due_at)}\n </p>\n </div>\n </div>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Fact label={adminText(\"Amount\")}>\n {formatNativeAmount(c.amount, c.currency)}\n </Fact>\n <Fact label={adminText(\"First outcome\")}>\n {c.miss_reason ? `missed · ${c.miss_reason}` : c.first_outcome}\n </Fact>\n <Fact label={adminText(\"Collected\")}>\n {c.collected_at\n ? `${formatDate(c.collected_at)}${c.recovered_by ? ` · ${c.recovered_by}` : \"\"}`\n : \"—\"}\n </Fact>\n <Fact label={c.outcome === \"open\" ? \"Closes\" : \"Closed\"}>\n {formatDate(c.closes_at)}\n </Fact>\n <Fact label={adminText(\"Subscription\")}>\n <To to={`/subscriptions/${c.subscription_id}`}>\n {shortId(c.subscription_id, 16)}\n </To>\n </Fact>\n <Fact label={adminText(\"Customer\")}>\n <To to={`/customers/${c.customer_id}`}>\n {shortId(c.customer_id, 16)}\n </To>\n </Fact>\n </div>\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"Attempts\"} />\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={attemptColumns}\n data={c.attempts ?? []}\n onRowClick={(row) => navigate(`/payments/attempts/${row.id}`)}\n emptyMessage={\n c.miss_reason ? \"Never attempted.\" : \"No attempts yet.\"\n }\n />\n </CardContent>\n </Card>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as e } from "./admin-utils-
|
|
1
|
+
import { f as e } from "./admin-utils-DnVY5fYd.js";
|
|
2
2
|
//#region src/admin/lib/auth.tsx
|
|
3
3
|
function t() {
|
|
4
4
|
let { merchants: t, activeMerchant: n, selectMerchant: r } = e();
|
|
@@ -11,4 +11,4 @@ function t() {
|
|
|
11
11
|
//#endregion
|
|
12
12
|
export { t };
|
|
13
13
|
|
|
14
|
-
//# sourceMappingURL=admin-auth-
|
|
14
|
+
//# sourceMappingURL=admin-auth-CiuZ-Hlm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-auth-
|
|
1
|
+
{"version":3,"file":"admin-auth-CiuZ-Hlm.js","names":[],"sources":["../src/admin/lib/auth.tsx"],"sourcesContent":["import { useAdminContext } from \"../context\"\n\n// BillingAdmin uses its host's session and merchant directory.\nexport function useAuth() {\n const { merchants, activeMerchant, selectMerchant } = useAdminContext()\n return { merchants, activeMerchant, selectMerchant }\n}\n\nexport function useSelectedMerchant() {\n return useAdminContext().activeMerchant?.slug\n}\n"],"mappings":";;AAGA,SAAgB,IAAU;CACxB,IAAM,EAAE,cAAW,mBAAgB,sBAAmB,EAAgB;CACtE,OAAO;EAAE;EAAW;EAAgB;CAAe;AACrD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./admin-utils-
|
|
1
|
+
import { t as e } from "./admin-utils-DnVY5fYd.js";
|
|
2
2
|
import { mergeProps as t } from "@base-ui/react/merge-props";
|
|
3
3
|
import { useRender as n } from "@base-ui/react/use-render";
|
|
4
4
|
import { cva as r } from "class-variance-authority";
|
|
@@ -28,4 +28,4 @@ function a({ className: r, variant: a = "default", render: o, ...s }) {
|
|
|
28
28
|
//#endregion
|
|
29
29
|
export { a as t };
|
|
30
30
|
|
|
31
|
-
//# sourceMappingURL=admin-badge-
|
|
31
|
+
//# sourceMappingURL=admin-badge-VCGbnfiN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-badge-
|
|
1
|
+
{"version":3,"file":"admin-badge-VCGbnfiN.js","names":[],"sources":["../src/admin/components/ui/badge.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"#orck/admin/lib/utils\"\n\nconst badgeVariants = cva(\n \"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n secondary:\n \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n destructive:\n \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n outline:\n \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n ghost:\n \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: useRender.ComponentProps<\"span\"> & VariantProps<typeof badgeVariants>) {\n return useRender({\n defaultTagName: \"span\",\n props: mergeProps<\"span\">(\n {\n className: cn(badgeVariants({ variant }), className),\n },\n props\n ),\n render,\n state: {\n slot: \"badge\",\n variant,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n"],"mappings":";;;;;AAMA,IAAM,IAAgB,EACpB,8eACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,WACE;EACF,aACE;EACF,SACE;EACF,OACE;EACF,MAAM;CACR,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CACF;AAEA,SAAS,EAAM,EACb,cACA,aAAU,WACV,WACA,GAAG,KACqE;CACxE,OAAO,EAAU;EACf,gBAAgB;EAChB,OAAO,EACL,EACE,WAAW,EAAG,EAAc,EAAE,WAAQ,CAAC,GAAG,CAAS,EACrD,GACA,CACF;EACA;EACA,OAAO;GACL,MAAM;GACN;EACF;CACF,CAAC;AACH"}
|