@openrails/billing-ui 0.249.0 → 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 +17 -0
- package/README.md +13 -13
- 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 +3 -3
- package/dist/cart.d.ts +4 -4
- package/dist/client/client.d.ts +4 -4
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/routes.d.ts +4 -4
- package/dist/client/generated/wire.d.ts +37 -40
- package/dist/client/types.d.ts +12 -17
- package/dist/{client-rFrCMrkn.js → client-HWr09qpX.js} +11 -13
- 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-B1TffejB.js → hooks-D9MR20BY.js} +2 -2
- package/dist/hooks-D9MR20BY.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +69 -69
- 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 +8 -8
- package/dist/{order-checkout.d.ts → order-payment.d.ts} +4 -4
- package/dist/product-list.d.ts +3 -3
- package/dist/psp.d.ts +2 -2
- package/dist/react/provider.d.ts +3 -3
- package/dist/react.js +1 -1
- 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-rFrCMrkn.js.map +0 -1
- package/dist/embedded-checkout.d.ts +0 -25
- package/dist/hooks-B1TffejB.js.map +0 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { E as e, l as t, p as n, w as r } from "./admin-utils-
|
|
2
|
-
import { t as i } from "./admin-button-
|
|
3
|
-
import { d as a, f as o, l as s } from "./admin-capabilities-
|
|
1
|
+
import { E as e, l as t, p as n, w as r } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as i } from "./admin-button-Oip73Plq.js";
|
|
3
|
+
import { d as a, f as o, l as s } from "./admin-capabilities-BGv7oG8v.js";
|
|
4
4
|
import { o as c } from "./admin-format-DoohJ7Fg.js";
|
|
5
|
-
import { a as l, n as u, o as d, r as f, s as p, t as m } from "./admin-table-
|
|
6
|
-
import { t as h } from "./admin-badge-
|
|
7
|
-
import { t as g } from "./admin-status-badge-
|
|
8
|
-
import { a as _, i as v, n as y, o as b, r as x, t as S } from "./admin-dialog-
|
|
9
|
-
import { t as C } from "./admin-label-
|
|
5
|
+
import { a as l, n as u, o as d, r as f, s as p, t as m } from "./admin-table-CWhiCb9d.js";
|
|
6
|
+
import { t as h } from "./admin-badge-VCGbnfiN.js";
|
|
7
|
+
import { t as g } from "./admin-status-badge-CwqIU8tK.js";
|
|
8
|
+
import { a as _, i as v, n as y, o as b, r as x, t as S } from "./admin-dialog-Ffx95AIT.js";
|
|
9
|
+
import { t as C } from "./admin-label-BzJpr3lg.js";
|
|
10
10
|
import { n as w } from "./admin-dialog-width-BPrgdYlj.js";
|
|
11
|
-
import { t as T } from "./admin-textarea-
|
|
12
|
-
import { a as E, o as D, r as O, t as k } from "./admin-card-
|
|
11
|
+
import { t as T } from "./admin-textarea-DK1Fq31x.js";
|
|
12
|
+
import { a as E, o as D, r as O, t as k } from "./admin-card-DGbi6ZHZ.js";
|
|
13
13
|
import * as A from "react";
|
|
14
14
|
import { useMutation as j, useQuery as M, useQueryClient as N } from "@tanstack/react-query";
|
|
15
15
|
import { jsx as P, jsxs as F } from "react/jsx-runtime";
|
|
@@ -214,4 +214,4 @@ function V({ finding: t, onClose: a }) {
|
|
|
214
214
|
//#endregion
|
|
215
215
|
export { L as OpsPage };
|
|
216
216
|
|
|
217
|
-
//# sourceMappingURL=admin-ops-
|
|
217
|
+
//# sourceMappingURL=admin-ops-Ch2-BmUp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-ops-B3mcr76u.js","names":[],"sources":["../src/admin/pages/ops/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport * as React from \"react\"\n\nimport { useForm } from \"@tanstack/react-form\"\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { useSearchParams } from \"#orck/admin/router\"\n\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Badge } from \"#orck/admin/components/ui/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 Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"#orck/admin/components/ui/dialog\"\nimport { Label } from \"#orck/admin/components/ui/label\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"#orck/admin/components/ui/table\"\nimport { Textarea } from \"#orck/admin/components/ui/textarea\"\nimport type { Finding } from \"#orck/admin/lib/api/types\"\nimport { DIALOG_FORM } from \"#orck/admin/lib/dialog-width\"\nimport { formatDate } from \"#orck/admin/lib/format\"\n\nimport { useMerchantConfig, useMerchantConfigUpdates, useMetrics } from \"#orck/admin/lib/capabilities\"\n\nexport function OpsPage() {\n return useMerchantConfig() ? <FindingsTab /> : null\n}\n\nconst severityTone: Record<string, string> = {\n critical: \"bg-failed-surface text-failed\",\n high: \"bg-held-surface text-held\",\n medium: \"bg-held-surface text-held\",\n low: \"bg-muted text-muted-foreground\",\n}\n\nfunction FindingsTab() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const canRead = useMerchantConfig()\n const canUpdate = useMerchantConfigUpdates()\n const metrics = useMetrics()\n const { data, isPending: loading } = useQuery(adminQueries.findings(canRead))\n const { data: gauges } = useQuery({\n ...adminQueries.findingSummary(),\n enabled: metrics,\n })\n const [resolving, setResolving] = React.useState<Finding | null>(null)\n // The bell and alert emails link one finding: ?finding=<id>.\n const [params] = useSearchParams()\n const linked = params.get(\"finding\")\n\n return (\n <div className=\"flex flex-col gap-4\">\n {metrics && gauges && (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {/* Each gauge says what is wrong with the MONEY, not what the check\n is called internally: a merchant reading \"freeloaders\" cannot tell\n whether that costs them anything. */}\n <Gauge label={adminText(\"Open issues\")} value={gauges.total_open} />\n <Gauge\n label={adminText(\"Paying, no access\")}\n value={gauges.orphaned_members}\n alert\n />\n <Gauge\n label={adminText(\"Access, not paying\")}\n value={gauges.freeloaders}\n alert\n />\n <Gauge\n label={adminText(\"Charged twice\")}\n value={gauges.duplicate_coverage}\n alert\n />\n </div>\n )}\n {loading ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n ) : !data?.data.length ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Nothing needs attention right now.\"} />\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Severity\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Type\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Subject\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Status\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Recommendation\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Last seen\"} />\n </TableHead>\n <TableHead />\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.data.map((f) => (\n <TableRow\n key={f.id}\n className={f.id === linked ? \"bg-primary/[0.06]\" : undefined}\n >\n <TableCell>\n <Badge\n variant=\"secondary\"\n className={severityTone[f.severity] ?? \"\"}\n >\n {f.severity}\n </Badge>\n </TableCell>\n <TableCell className=\"text-xs\">{f.finding_type}</TableCell>\n <TableCell className=\"max-w-52 truncate text-xs\">\n {f.subject_key}\n </TableCell>\n <TableCell>\n <StatusBadge status={f.status} />\n </TableCell>\n <TableCell>\n {f.recommendation?.action ?? f.recommended_action ?? \"—\"}\n </TableCell>\n <TableCell>{formatDate(f.last_seen_at)}</TableCell>\n <TableCell className=\"text-right\">\n {canUpdate && !f.resolved_at && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setResolving(f)}\n >\n <AdminMessage id={\"Resolve\"} />\n </Button>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n {resolving && (\n <ResolveFindingDialog\n finding={resolving}\n onClose={() => setResolving(null)}\n />\n )}\n </div>\n )\n}\n\nfunction Gauge({\n label,\n value,\n alert,\n}: {\n label: string\n value: number\n alert?: boolean\n}) {\n return (\n <Card>\n <CardHeader className=\"pb-1\">\n <CardTitle className=\"text-xs font-normal text-muted-foreground uppercase\">\n {label}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <p\n className={`text-2xl font-semibold ${alert && value > 0 ? \"text-failed\" : \"\"}`}\n >\n {value}\n </p>\n </CardContent>\n </Card>\n )\n}\n\nfunction ResolveFindingDialog({\n finding,\n onClose,\n}: {\n finding: Finding\n onClose: () => void\n}) {\n const { toast, toastApiError, adminMutations } = useAdminServices()\n\n const { id: adminId } = useAdminUI()\n\n const queryClient = useQueryClient()\n const resolution = useMutation(adminMutations.resolveFinding(queryClient))\n const form = useForm({ defaultValues: { notes: \"\" } })\n const canApprove = Boolean(finding.recommendation)\n\n const resolve = async (outcome: \"approve\" | \"ignore\") => {\n try {\n await resolution.mutateAsync({\n id: finding.id,\n outcome,\n notes: form.state.values.notes,\n })\n toast.success(\n outcome === \"approve\" ? \"Recommendation executed\" : \"Finding ignored\"\n )\n onClose()\n } catch (err) {\n toastApiError(err, \"Resolve finding\")\n }\n }\n\n return (\n <Dialog open onOpenChange={(o) => !o && onClose()}>\n <DialogContent className={DIALOG_FORM}>\n <DialogHeader>\n <DialogTitle>\n <AdminMessage id={\"Resolve finding\"} />\n </DialogTitle>\n <DialogDescription>\n {finding.finding_type} · {finding.subject_key}\n </DialogDescription>\n </DialogHeader>\n {finding.recommendation ? (\n <div className=\"rounded-md bg-muted p-3 text-sm\">\n <p className=\"font-medium\">\n <AdminMessage id={\"Recommended: \"} />\n {finding.recommendation.action}\n </p>\n {finding.recommendation.params && (\n <pre className=\"mt-1 overflow-auto text-xs\">\n {JSON.stringify(finding.recommendation.params, null, 2)}\n </pre>\n )}\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage\n id={\n \"Nothing here can be fixed automatically. You can only note why you are leaving it.\"\n }\n />\n </p>\n )}\n <form.Field name=\"notes\">\n {(field) => (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={adminId(\"f-notes\")}>\n <AdminMessage id={\"Notes \"} />\n {canApprove ? \"(required to ignore)\" : \"(required)\"}\n </Label>\n <Textarea\n id={adminId(\"f-notes\")}\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(event) => field.handleChange(event.target.value)}\n />\n </div>\n )}\n </form.Field>\n <DialogFooter>\n <form.Subscribe selector={(state) => state.values.notes}>\n {(notes) => (\n <Button\n variant=\"outline\"\n disabled={resolution.isPending || !notes.trim()}\n onClick={() => resolve(\"ignore\")}\n >\n <AdminMessage id={\"Ignore\"} />\n </Button>\n )}\n </form.Subscribe>\n {canApprove && (\n <Button\n disabled={resolution.isPending}\n onClick={() => resolve(\"approve\")}\n >\n {resolution.isPending ? \"Working…\" : \"Approve recommendation\"}\n </Button>\n )}\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-ops-Ch2-BmUp.js","names":[],"sources":["../src/admin/pages/ops/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport * as React from \"react\"\n\nimport { useForm } from \"@tanstack/react-form\"\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { useSearchParams } from \"#orck/admin/router\"\n\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Badge } from \"#orck/admin/components/ui/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 Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"#orck/admin/components/ui/dialog\"\nimport { Label } from \"#orck/admin/components/ui/label\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"#orck/admin/components/ui/table\"\nimport { Textarea } from \"#orck/admin/components/ui/textarea\"\nimport type { Finding } from \"#orck/admin/lib/api/types\"\nimport { DIALOG_FORM } from \"#orck/admin/lib/dialog-width\"\nimport { formatDate } from \"#orck/admin/lib/format\"\n\nimport { useMerchantConfig, useMerchantConfigUpdates, useMetrics } from \"#orck/admin/lib/capabilities\"\n\nexport function OpsPage() {\n return useMerchantConfig() ? <FindingsTab /> : null\n}\n\nconst severityTone: Record<string, string> = {\n critical: \"bg-failed-surface text-failed\",\n high: \"bg-held-surface text-held\",\n medium: \"bg-held-surface text-held\",\n low: \"bg-muted text-muted-foreground\",\n}\n\nfunction FindingsTab() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const canRead = useMerchantConfig()\n const canUpdate = useMerchantConfigUpdates()\n const metrics = useMetrics()\n const { data, isPending: loading } = useQuery(adminQueries.findings(canRead))\n const { data: gauges } = useQuery({\n ...adminQueries.findingSummary(),\n enabled: metrics,\n })\n const [resolving, setResolving] = React.useState<Finding | null>(null)\n // The bell and alert emails link one finding: ?finding=<id>.\n const [params] = useSearchParams()\n const linked = params.get(\"finding\")\n\n return (\n <div className=\"flex flex-col gap-4\">\n {metrics && gauges && (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {/* Each gauge says what is wrong with the MONEY, not what the check\n is called internally: a merchant reading \"freeloaders\" cannot tell\n whether that costs them anything. */}\n <Gauge label={adminText(\"Open issues\")} value={gauges.total_open} />\n <Gauge\n label={adminText(\"Paying, no access\")}\n value={gauges.orphaned_members}\n alert\n />\n <Gauge\n label={adminText(\"Access, not paying\")}\n value={gauges.freeloaders}\n alert\n />\n <Gauge\n label={adminText(\"Charged twice\")}\n value={gauges.duplicate_coverage}\n alert\n />\n </div>\n )}\n {loading ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Loading…\"} />\n </p>\n ) : !data?.data.length ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"Nothing needs attention right now.\"} />\n </p>\n ) : (\n <div className=\"overflow-x-auto rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Severity\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Type\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Subject\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Status\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Recommendation\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Last seen\"} />\n </TableHead>\n <TableHead />\n </TableRow>\n </TableHeader>\n <TableBody>\n {data.data.map((f) => (\n <TableRow\n key={f.id}\n className={f.id === linked ? \"bg-primary/[0.06]\" : undefined}\n >\n <TableCell>\n <Badge\n variant=\"secondary\"\n className={severityTone[f.severity] ?? \"\"}\n >\n {f.severity}\n </Badge>\n </TableCell>\n <TableCell className=\"text-xs\">{f.finding_type}</TableCell>\n <TableCell className=\"max-w-52 truncate text-xs\">\n {f.subject_key}\n </TableCell>\n <TableCell>\n <StatusBadge status={f.status} />\n </TableCell>\n <TableCell>\n {f.recommendation?.action ?? f.recommended_action ?? \"—\"}\n </TableCell>\n <TableCell>{formatDate(f.last_seen_at)}</TableCell>\n <TableCell className=\"text-right\">\n {canUpdate && !f.resolved_at && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setResolving(f)}\n >\n <AdminMessage id={\"Resolve\"} />\n </Button>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n {resolving && (\n <ResolveFindingDialog\n finding={resolving}\n onClose={() => setResolving(null)}\n />\n )}\n </div>\n )\n}\n\nfunction Gauge({\n label,\n value,\n alert,\n}: {\n label: string\n value: number\n alert?: boolean\n}) {\n return (\n <Card>\n <CardHeader className=\"pb-1\">\n <CardTitle className=\"text-xs font-normal text-muted-foreground uppercase\">\n {label}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <p\n className={`text-2xl font-semibold ${alert && value > 0 ? \"text-failed\" : \"\"}`}\n >\n {value}\n </p>\n </CardContent>\n </Card>\n )\n}\n\nfunction ResolveFindingDialog({\n finding,\n onClose,\n}: {\n finding: Finding\n onClose: () => void\n}) {\n const { toast, toastApiError, adminMutations } = useAdminServices()\n\n const { id: adminId } = useAdminUI()\n\n const queryClient = useQueryClient()\n const resolution = useMutation(adminMutations.resolveFinding(queryClient))\n const form = useForm({ defaultValues: { notes: \"\" } })\n const canApprove = Boolean(finding.recommendation)\n\n const resolve = async (outcome: \"approve\" | \"ignore\") => {\n try {\n await resolution.mutateAsync({\n id: finding.id,\n outcome,\n notes: form.state.values.notes,\n })\n toast.success(\n outcome === \"approve\" ? \"Recommendation executed\" : \"Finding ignored\"\n )\n onClose()\n } catch (err) {\n toastApiError(err, \"Resolve finding\")\n }\n }\n\n return (\n <Dialog open onOpenChange={(o) => !o && onClose()}>\n <DialogContent className={DIALOG_FORM}>\n <DialogHeader>\n <DialogTitle>\n <AdminMessage id={\"Resolve finding\"} />\n </DialogTitle>\n <DialogDescription>\n {finding.finding_type} · {finding.subject_key}\n </DialogDescription>\n </DialogHeader>\n {finding.recommendation ? (\n <div className=\"rounded-md bg-muted p-3 text-sm\">\n <p className=\"font-medium\">\n <AdminMessage id={\"Recommended: \"} />\n {finding.recommendation.action}\n </p>\n {finding.recommendation.params && (\n <pre className=\"mt-1 overflow-auto text-xs\">\n {JSON.stringify(finding.recommendation.params, null, 2)}\n </pre>\n )}\n </div>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage\n id={\n \"Nothing here can be fixed automatically. You can only note why you are leaving it.\"\n }\n />\n </p>\n )}\n <form.Field name=\"notes\">\n {(field) => (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={adminId(\"f-notes\")}>\n <AdminMessage id={\"Notes \"} />\n {canApprove ? \"(required to ignore)\" : \"(required)\"}\n </Label>\n <Textarea\n id={adminId(\"f-notes\")}\n value={field.state.value}\n onBlur={field.handleBlur}\n onChange={(event) => field.handleChange(event.target.value)}\n />\n </div>\n )}\n </form.Field>\n <DialogFooter>\n <form.Subscribe selector={(state) => state.values.notes}>\n {(notes) => (\n <Button\n variant=\"outline\"\n disabled={resolution.isPending || !notes.trim()}\n onClick={() => resolve(\"ignore\")}\n >\n <AdminMessage id={\"Ignore\"} />\n </Button>\n )}\n </form.Subscribe>\n {canApprove && (\n <Button\n disabled={resolution.isPending}\n onClick={() => resolve(\"approve\")}\n >\n {resolution.isPending ? \"Working…\" : \"Approve recommendation\"}\n </Button>\n )}\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { E as e, l as t, p as n, r, w as i } from "./admin-utils-
|
|
2
|
-
import { t as a } from "./admin-button-
|
|
3
|
-
import { t as o } from "./admin-input-
|
|
1
|
+
import { E as e, l as t, p as n, r, w as i } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as a } from "./admin-button-Oip73Plq.js";
|
|
3
|
+
import { t as o } from "./admin-input-DO5lvCLL.js";
|
|
4
4
|
import { o as s, s as c, u as l } from "./admin-format-DoohJ7Fg.js";
|
|
5
|
-
import { i as u, n as d } from "./admin-dom-
|
|
6
|
-
import { t as f } from "./admin-status-badge-
|
|
7
|
-
import { t as p } from "./admin-label-
|
|
8
|
-
import { t as m } from "./admin-data-table-
|
|
5
|
+
import { i as u, n as d } from "./admin-dom-lnNSQ7ke.js";
|
|
6
|
+
import { t as f } from "./admin-status-badge-CwqIU8tK.js";
|
|
7
|
+
import { t as p } from "./admin-label-BzJpr3lg.js";
|
|
8
|
+
import { t as m } from "./admin-data-table-CgeWv__T.js";
|
|
9
9
|
import { useState as h } from "react";
|
|
10
10
|
import { useQuery as g } from "@tanstack/react-query";
|
|
11
11
|
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
@@ -189,4 +189,4 @@ function C({ filters: t, onApply: n }) {
|
|
|
189
189
|
//#endregion
|
|
190
190
|
export { S as OrdersPage };
|
|
191
191
|
|
|
192
|
-
//# sourceMappingURL=admin-orders-
|
|
192
|
+
//# sourceMappingURL=admin-orders-8XzHf7b-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-orders-dxC99Idl.js","names":[],"sources":["../src/admin/pages/orders/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { useState } from \"react\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport { Link, useSearchParams } from \"#orck/admin/router\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\nimport { CursorPager } from \"#orck/admin/components/cursor-pager\"\nimport { DataTable } from \"#orck/admin/components/data-table\"\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Input } from \"#orck/admin/components/ui/input\"\nimport { Label } from \"#orck/admin/components/ui/label\"\n\nimport type { Order } from \"#orck/client/generated/wire\"\nimport type { OrderFilters } from \"#orck/admin/lib/api/order-endpoints\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport { formatDate, formatNativeAmount, shortId } from \"#orck/admin/lib/format\"\n\n// dueAt is when an order is owed: a usage order's or a renewal's due date.\nconst dueAt = (order: Order) =>\n order.usage?.due_at ?? order.renewal?.due_at ?? null\nconst columns: ColumnDef<Order, unknown>[] = [\n {\n header: \"Order\",\n cell: ({ row }) => (\n <Link className=\"underline\" to={`/orders/${row.original.id}`}>\n {row.original.number ?? shortId(row.original.id)}\n </Link>\n ),\n },\n {\n header: \"Customer\",\n cell: ({ row }) => (\n <Link to={`/customers/${row.original.customer_id}`}>\n {shortId(row.original.customer_id)}\n </Link>\n ),\n },\n { header: \"Origin\", cell: ({ row }) => row.original.origin },\n {\n header: \"Status\",\n cell: ({ row }) => (\n <span className=\"flex gap-1\">\n <StatusBadge status={row.original.status} />\n {/* Past grace: the customer's new usage in this currency is refused. */}\n {row.original.usage?.delinquent && <StatusBadge status=\"delinquent\" />}\n </span>\n ),\n },\n {\n header: \"Total\",\n cell: ({ row }) =>\n formatNativeAmount(row.original.total, row.original.currency),\n },\n {\n header: \"Unpaid\",\n cell: ({ row }) =>\n row.original.usage\n ? formatNativeAmount(\n row.original.usage.amount_due,\n row.original.currency\n )\n : \"—\",\n },\n { header: \"Due\", cell: ({ row }) => formatDate(dueAt(row.original)) },\n { header: \"Created\", cell: ({ row }) => formatDate(row.original.created_at) },\n]\nexport function OrdersPage() {\n const { orderQueries } = useAdminServices()\n\n const [params, setParams] = useSearchParams()\n const filters: OrderFilters = Object.fromEntries(\n [\"customer_id\", \"origin\", \"status\", \"overdue\"].flatMap((key) =>\n params.get(key) ? [[key, params.get(key)!]] : []\n )\n )\n const paging = useUrlCursor(25)\n const { data, isPending, isFetching, error } = useQuery(\n orderQueries.list(filters, paging.size, paging.cursor)\n )\n\n return (\n <div className=\"flex flex-col gap-5\">\n <div>\n <h1 className=\"text-xl font-semibold\">\n <AdminMessage id={\"Orders\"} />\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage\n id={\n \"Purchases, subscription renewals and usage billed in arrears: what each owes and how it was paid.\"\n }\n />\n </p>\n </div>\n <OrderFiltersForm\n key={JSON.stringify(filters)}\n filters={filters}\n onApply={(next) => {\n const p = new URLSearchParams()\n for (const [key, value] of Object.entries(next)) {\n if (value?.trim()) p.set(key, value.trim())\n }\n setParams(p)\n }}\n />\n {error ? (\n <p role=\"alert\" className=\"text-destructive\">\n {error.message}\n </p>\n ) : (\n <>\n <DataTable\n columns={columns}\n data={data?.data ?? []}\n loading={isPending}\n emptyMessage=\"No orders match these filters.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </>\n )}\n </div>\n )\n}\n\nfunction OrderFiltersForm({\n filters,\n onApply,\n}: {\n filters: OrderFilters\n onApply: (filters: OrderFilters) => void\n}) {\n const { id: adminId } = useAdminUI()\n\n const [draft, setDraft] = useState<OrderFilters>(filters)\n const setFilter = (key: string, value: string) =>\n setDraft((old) => ({ ...old, [key]: value }))\n return (\n <form\n className=\"grid gap-3 md:grid-cols-3\"\n onSubmit={(event) => {\n event.preventDefault()\n onApply(draft)\n }}\n >\n <div>\n <Label htmlFor={adminId(\"order-customer\")}>\n <AdminMessage id={\"Customer ID\"} />\n </Label>\n <Input\n id={adminId(\"order-customer\")}\n value={draft.customer_id ?? \"\"}\n onChange={(e) => setFilter(\"customer_id\", e.target.value.trim())}\n />\n </div>\n <div>\n <Label htmlFor={adminId(\"order-origin\")}>\n <AdminMessage id={\"Origin\"} />\n </Label>\n <select\n id={adminId(\"order-origin\")}\n className=\"h-9 w-full rounded-md border bg-background px-2\"\n value={draft.origin ?? \"\"}\n onChange={(e) => setFilter(\"origin\", e.target.value)}\n >\n <option value=\"\">\n <AdminMessage id={\"All origins\"} />\n </option>\n {[\"customer\", \"merchant\", \"subscription\", \"usage\"].map((origin) => (\n <option key={origin} value={origin}>\n {origin}\n </option>\n ))}\n </select>\n </div>\n <div>\n <Label htmlFor={adminId(\"order-status\")}>\n <AdminMessage id={\"Status\"} />\n </Label>\n <select\n id={adminId(\"order-status\")}\n className=\"h-9 w-full rounded-md border bg-background px-2\"\n value={draft.status ?? \"\"}\n onChange={(e) => setFilter(\"status\", e.target.value)}\n >\n <option value=\"\">\n <AdminMessage id={\"All statuses\"} />\n </option>\n {[\n \"open\",\n \"processing\",\n \"complete\",\n \"canceled\",\n \"expired\",\n \"void\",\n \"uncollectible\",\n ].map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n <label className=\"flex items-center gap-2 text-sm md:col-span-3\">\n <input\n type=\"checkbox\"\n checked={draft.overdue === \"true\"}\n onChange={(e) => setFilter(\"overdue\", e.target.checked ? \"true\" : \"\")}\n />\n <AdminMessage id={\"Overdue only: still owed past the due date\"} />\n </label>\n <div className=\"flex gap-2 md:col-span-3\">\n <Button type=\"submit\">\n <AdminMessage id={\"Apply filters\"} />\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDraft({})\n onApply({})\n }}\n >\n <AdminMessage id={\"Clear filters\"} />\n </Button>\n </div>\n </form>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-orders-8XzHf7b-.js","names":[],"sources":["../src/admin/pages/orders/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { useState } from \"react\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport { Link, useSearchParams } from \"#orck/admin/router\"\nimport type { ColumnDef } from \"@tanstack/react-table\"\nimport { CursorPager } from \"#orck/admin/components/cursor-pager\"\nimport { DataTable } from \"#orck/admin/components/data-table\"\nimport { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Input } from \"#orck/admin/components/ui/input\"\nimport { Label } from \"#orck/admin/components/ui/label\"\n\nimport type { Order } from \"#orck/client/generated/wire\"\nimport type { OrderFilters } from \"#orck/admin/lib/api/order-endpoints\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport { formatDate, formatNativeAmount, shortId } from \"#orck/admin/lib/format\"\n\n// dueAt is when an order is owed: a usage order's or a renewal's due date.\nconst dueAt = (order: Order) =>\n order.usage?.due_at ?? order.renewal?.due_at ?? null\nconst columns: ColumnDef<Order, unknown>[] = [\n {\n header: \"Order\",\n cell: ({ row }) => (\n <Link className=\"underline\" to={`/orders/${row.original.id}`}>\n {row.original.number ?? shortId(row.original.id)}\n </Link>\n ),\n },\n {\n header: \"Customer\",\n cell: ({ row }) => (\n <Link to={`/customers/${row.original.customer_id}`}>\n {shortId(row.original.customer_id)}\n </Link>\n ),\n },\n { header: \"Origin\", cell: ({ row }) => row.original.origin },\n {\n header: \"Status\",\n cell: ({ row }) => (\n <span className=\"flex gap-1\">\n <StatusBadge status={row.original.status} />\n {/* Past grace: the customer's new usage in this currency is refused. */}\n {row.original.usage?.delinquent && <StatusBadge status=\"delinquent\" />}\n </span>\n ),\n },\n {\n header: \"Total\",\n cell: ({ row }) =>\n formatNativeAmount(row.original.total, row.original.currency),\n },\n {\n header: \"Unpaid\",\n cell: ({ row }) =>\n row.original.usage\n ? formatNativeAmount(\n row.original.usage.amount_due,\n row.original.currency\n )\n : \"—\",\n },\n { header: \"Due\", cell: ({ row }) => formatDate(dueAt(row.original)) },\n { header: \"Created\", cell: ({ row }) => formatDate(row.original.created_at) },\n]\nexport function OrdersPage() {\n const { orderQueries } = useAdminServices()\n\n const [params, setParams] = useSearchParams()\n const filters: OrderFilters = Object.fromEntries(\n [\"customer_id\", \"origin\", \"status\", \"overdue\"].flatMap((key) =>\n params.get(key) ? [[key, params.get(key)!]] : []\n )\n )\n const paging = useUrlCursor(25)\n const { data, isPending, isFetching, error } = useQuery(\n orderQueries.list(filters, paging.size, paging.cursor)\n )\n\n return (\n <div className=\"flex flex-col gap-5\">\n <div>\n <h1 className=\"text-xl font-semibold\">\n <AdminMessage id={\"Orders\"} />\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage\n id={\n \"Purchases, subscription renewals and usage billed in arrears: what each owes and how it was paid.\"\n }\n />\n </p>\n </div>\n <OrderFiltersForm\n key={JSON.stringify(filters)}\n filters={filters}\n onApply={(next) => {\n const p = new URLSearchParams()\n for (const [key, value] of Object.entries(next)) {\n if (value?.trim()) p.set(key, value.trim())\n }\n setParams(p)\n }}\n />\n {error ? (\n <p role=\"alert\" className=\"text-destructive\">\n {error.message}\n </p>\n ) : (\n <>\n <DataTable\n columns={columns}\n data={data?.data ?? []}\n loading={isPending}\n emptyMessage=\"No orders match these filters.\"\n />\n <CursorPager\n pages={paging}\n rows={data?.data?.length ?? 0}\n nextCursor={data?.next_cursor}\n busy={isFetching}\n />\n </>\n )}\n </div>\n )\n}\n\nfunction OrderFiltersForm({\n filters,\n onApply,\n}: {\n filters: OrderFilters\n onApply: (filters: OrderFilters) => void\n}) {\n const { id: adminId } = useAdminUI()\n\n const [draft, setDraft] = useState<OrderFilters>(filters)\n const setFilter = (key: string, value: string) =>\n setDraft((old) => ({ ...old, [key]: value }))\n return (\n <form\n className=\"grid gap-3 md:grid-cols-3\"\n onSubmit={(event) => {\n event.preventDefault()\n onApply(draft)\n }}\n >\n <div>\n <Label htmlFor={adminId(\"order-customer\")}>\n <AdminMessage id={\"Customer ID\"} />\n </Label>\n <Input\n id={adminId(\"order-customer\")}\n value={draft.customer_id ?? \"\"}\n onChange={(e) => setFilter(\"customer_id\", e.target.value.trim())}\n />\n </div>\n <div>\n <Label htmlFor={adminId(\"order-origin\")}>\n <AdminMessage id={\"Origin\"} />\n </Label>\n <select\n id={adminId(\"order-origin\")}\n className=\"h-9 w-full rounded-md border bg-background px-2\"\n value={draft.origin ?? \"\"}\n onChange={(e) => setFilter(\"origin\", e.target.value)}\n >\n <option value=\"\">\n <AdminMessage id={\"All origins\"} />\n </option>\n {[\"customer\", \"merchant\", \"subscription\", \"usage\"].map((origin) => (\n <option key={origin} value={origin}>\n {origin}\n </option>\n ))}\n </select>\n </div>\n <div>\n <Label htmlFor={adminId(\"order-status\")}>\n <AdminMessage id={\"Status\"} />\n </Label>\n <select\n id={adminId(\"order-status\")}\n className=\"h-9 w-full rounded-md border bg-background px-2\"\n value={draft.status ?? \"\"}\n onChange={(e) => setFilter(\"status\", e.target.value)}\n >\n <option value=\"\">\n <AdminMessage id={\"All statuses\"} />\n </option>\n {[\n \"open\",\n \"processing\",\n \"complete\",\n \"canceled\",\n \"expired\",\n \"void\",\n \"uncollectible\",\n ].map((status) => (\n <option key={status} value={status}>\n {status}\n </option>\n ))}\n </select>\n </div>\n <label className=\"flex items-center gap-2 text-sm md:col-span-3\">\n <input\n type=\"checkbox\"\n checked={draft.overdue === \"true\"}\n onChange={(e) => setFilter(\"overdue\", e.target.checked ? \"true\" : \"\")}\n />\n <AdminMessage id={\"Overdue only: still owed past the due date\"} />\n </label>\n <div className=\"flex gap-2 md:col-span-3\">\n <Button type=\"submit\">\n <AdminMessage id={\"Apply filters\"} />\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setDraft({})\n onApply({})\n }}\n >\n <AdminMessage id={\"Clear filters\"} />\n </Button>\n </div>\n </form>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { E as e, l as t, p as n, s as r, w as i } from "./admin-utils-
|
|
2
|
-
import { t as a } from "./admin-button-
|
|
3
|
-
import { t as o } from "./admin-input-
|
|
1
|
+
import { E as e, l as t, p as n, s as r, w as i } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as a } from "./admin-button-Oip73Plq.js";
|
|
3
|
+
import { t as o } from "./admin-input-DO5lvCLL.js";
|
|
4
4
|
import { n as s, o as c, p as l, r as u, s as d, u as f } from "./admin-format-DoohJ7Fg.js";
|
|
5
|
-
import { a as p, i as m, n as h, r as g, t as _ } from "./admin-select-
|
|
6
|
-
import { i as v, n as y } from "./admin-dom-
|
|
7
|
-
import { t as b } from "./admin-status-badge-
|
|
8
|
-
import { t as x } from "./admin-data-table-
|
|
5
|
+
import { a as p, i as m, n as h, r as g, t as _ } from "./admin-select-CUXvh6j1.js";
|
|
6
|
+
import { i as v, n as y } from "./admin-dom-lnNSQ7ke.js";
|
|
7
|
+
import { t as b } from "./admin-status-badge-CwqIU8tK.js";
|
|
8
|
+
import { t as x } from "./admin-data-table-CgeWv__T.js";
|
|
9
9
|
import { t as S } from "./admin-csv-CPoNZj2D.js";
|
|
10
|
-
import { i as C, r as w, t as T } from "./admin-tabs-
|
|
10
|
+
import { i as C, r as w, t as T } from "./admin-tabs-Cjm5a6UJ.js";
|
|
11
11
|
import * as E from "react";
|
|
12
12
|
import { useMutation as D, useQuery as O } from "@tanstack/react-query";
|
|
13
13
|
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
@@ -243,4 +243,4 @@ function R() {
|
|
|
243
243
|
//#endregion
|
|
244
244
|
export { R as PaymentsPage };
|
|
245
245
|
|
|
246
|
-
//# sourceMappingURL=admin-payments-
|
|
246
|
+
//# sourceMappingURL=admin-payments-pNLNIU0X.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-payments-Bs7HSfP0.js","names":[],"sources":["../src/admin/pages/payments/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { HugeiconsIcon } from \"@hugeicons/react\"\nimport {\n Cancel01Icon,\n Download01Icon,\n Search01Icon,\n} from \"@hugeicons/core-free-icons\"\nimport * as React from \"react\"\nimport { useNavigate, useSearchParams } from \"#orck/admin/router\"\nimport { useMutation, 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 { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport { Input } from \"#orck/admin/components/ui/input\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"#orck/admin/components/ui/select\"\nimport { Tabs, TabsList, TabsTrigger } from \"#orck/admin/components/ui/tabs\"\nimport type { PaymentFilters } from \"#orck/admin/lib/api/endpoints\"\nimport type { Payment } from \"#orck/client/generated/wire\"\nimport { downloadCsv } from \"#orck/admin/lib/csv\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport {\n currencyScale,\n formatNativeAmount,\n formatDate,\n customerName,\n shortId,\n unitsToDecimal,\n} from \"#orck/admin/lib/format\"\n\nconst RAILS = [\"nmi\", \"ccbill\", \"stripe\", \"solana\"]\nconst KINDS = [\n [\"\", \"All\"],\n [\"charge\", \"Charges\"],\n [\"refund\", \"Refunds\"],\n [\"chargeback\", \"Chargebacks\"],\n] as const\n\nconst columns: ColumnDef<Payment, unknown>[] = [\n {\n header: \"Amount\",\n cell: ({ row }) => (\n <span className=\"font-medium tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ),\n },\n {\n header: \"Status\",\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n { header: \"Kind\", cell: ({ row }) => row.original.kind },\n // Off-rail payments name their channel instead.\n {\n header: \"Rail\",\n cell: ({ row }) => row.original.rail ?? row.original.channel,\n },\n {\n header: \"Payment\",\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {shortId(row.original.id, 16)}\n </span>\n ),\n },\n {\n header: \"Refunded\",\n cell: ({ row }) =>\n row.original.amount_refunded !== \"0\" ? (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatNativeAmount(\n row.original.amount_refunded,\n row.original.currency\n )}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n ),\n },\n {\n header: \"Created\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.created_at)}\n </span>\n ),\n },\n]\n\n// csvAmount exports an exact major-unit decimal; an amount that cannot be\n// represented exactly aborts the export rather than writing a wrong figure.\nfunction csvAmount(amount: string, currency: string): string {\n const scale = currencyScale(currency)\n const decimal = scale === undefined ? null : unitsToDecimal(amount, scale)\n if (decimal === null)\n throw new Error(`${currency} amount ${amount} cannot be exported exactly`)\n return decimal\n}\n\nexport function PaymentsPage() {\n const { toast, toastApiError, adminMutations, adminQueries } =\n useAdminServices()\n\n const { text: adminText } = useAdminUI()\n\n const [params, setParams] = useSearchParams()\n const rail = params.get(\"rail\") ?? \"\"\n const kind = (params.get(\"kind\") ?? \"\") as Payment[\"kind\"] | \"\"\n const userId = params.get(\"customer_id\") ?? \"\"\n const customerLabel = params.get(\"customer\") ?? \"\"\n const paging = useUrlCursor()\n const [input, setInput] = React.useState(\"\")\n const navigate = useNavigate()\n const customerLookup = useMutation(adminMutations.findCustomer())\n const exportPayments = useMutation(adminMutations.exportPayments())\n\n const filters: PaymentFilters = {\n rail: rail || undefined,\n kind: kind || undefined,\n customer_id: userId || undefined,\n }\n const {\n data,\n isPending: loading,\n isFetching,\n } = useQuery(adminQueries.payments(filters, paging.size, paging.cursor))\n\n const setParam = (key: string, value: string) => {\n const p = new URLSearchParams(params)\n if (value) p.set(key, value)\n else p.delete(key)\n p.delete(\"cursor\")\n setParams(p)\n }\n\n // The payments API has no free-text search: resolve the term to a customer,\n // then filter by its id.\n const searchCustomer = async () => {\n const term = input.trim()\n if (!term) return\n try {\n const c = await customerLookup.mutateAsync(term)\n if (!c) {\n toast.info(\"No customer matches\")\n return\n }\n const p = new URLSearchParams(params)\n p.set(\"customer_id\", c.id)\n p.set(\"customer\", customerName(c))\n p.delete(\"cursor\")\n setParams(p)\n setInput(\"\")\n } catch (err) {\n toastApiError(err, \"Search customers\")\n }\n }\n\n const clearCustomer = () => {\n const p = new URLSearchParams(params)\n p.delete(\"customer_id\")\n p.delete(\"customer\")\n p.delete(\"cursor\")\n setParams(p)\n }\n\n const exportCsv = async () => {\n try {\n const rows = await exportPayments.mutateAsync(filters)\n downloadCsv(\n `payments-${new Date().toISOString().slice(0, 10)}.csv`,\n [\n \"id\",\n \"kind\",\n \"status\",\n \"channel\",\n \"amount\",\n \"amount_refunded\",\n \"currency\",\n \"rail\",\n \"customer_id\",\n \"transaction_id\",\n \"created_at\",\n ],\n rows.map((r) => [\n r.id,\n r.kind,\n r.status,\n r.channel,\n csvAmount(r.amount, r.currency),\n csvAmount(r.amount_refunded, r.currency),\n r.currency,\n r.rail,\n r.customer_id,\n r.transaction_id,\n r.created_at,\n ])\n )\n } catch (err) {\n toastApiError(err, \"Export payments\")\n }\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Payments\"} />\n </h1>\n <div className=\"flex flex-wrap items-center gap-3\">\n <form\n className=\"relative\"\n aria-busy={customerLookup.isPending}\n onSubmit={(e) => {\n e.preventDefault()\n void searchCustomer()\n }}\n >\n <HugeiconsIcon\n icon={Search01Icon}\n className=\"absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n className=\"w-64 pl-8\"\n placeholder={adminText(\"Search customer email, ref, or id…\")}\n value={input}\n disabled={customerLookup.isPending}\n onChange={(e) => setInput(e.target.value)}\n />\n </form>\n <Select\n items={[\n { value: \"all\", label: \"All rails\" },\n ...RAILS.map((r) => ({ value: r, label: r })),\n ]}\n value={rail || \"all\"}\n onValueChange={(v) => setParam(\"rail\", !v || v === \"all\" ? \"\" : v)}\n >\n <SelectTrigger className=\"w-36\">\n <SelectValue placeholder={adminText(\"Rail\")} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n <AdminMessage id={\"All rails\"} />\n </SelectItem>\n {RAILS.map((r) => (\n <SelectItem key={r} value={r}>\n {r}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Button\n size=\"sm\"\n onClick={exportCsv}\n disabled={exportPayments.isPending || loading || !data?.data.length}\n >\n <HugeiconsIcon icon={Download01Icon} className=\"size-4\" />\n {exportPayments.isPending ? \"Exporting…\" : \"Export CSV\"}\n </Button>\n </div>\n </div>\n\n <Tabs value={kind} onValueChange={(v) => setParam(\"kind\", v ?? \"\")}>\n <TabsList\n variant=\"line\"\n className=\"w-full justify-start gap-6 rounded-none p-0\"\n >\n {KINDS.map(([value, label]) => (\n <TabsTrigger\n key={value}\n value={value}\n className=\"flex-none px-0 after:bg-primary group-data-horizontal/tabs:after:bottom-[-1px]\"\n >\n {label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n\n {userId ? (\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">\n <AdminMessage id={\"Customer\"} />\n </span>\n <span className=\"inline-flex items-center gap-1 rounded-md bg-muted py-0.5 pr-1 pl-2 font-medium\">\n {customerLabel || shortId(userId, 13)}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-5\"\n aria-label={adminText(\"Clear customer filter\")}\n onClick={clearCustomer}\n >\n <HugeiconsIcon icon={Cancel01Icon} className=\"size-3\" />\n </Button>\n </span>\n </div>\n ) : null}\n\n <DataTable\n columns={columns}\n data={data?.data ?? []}\n loading={loading}\n onRowClick={(row) => navigate(`/payments/${row.id}`)}\n emptyMessage=\"No payments 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-payments-pNLNIU0X.js","names":[],"sources":["../src/admin/pages/payments/index.tsx"],"sourcesContent":["import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { HugeiconsIcon } from \"@hugeicons/react\"\nimport {\n Cancel01Icon,\n Download01Icon,\n Search01Icon,\n} from \"@hugeicons/core-free-icons\"\nimport * as React from \"react\"\nimport { useNavigate, useSearchParams } from \"#orck/admin/router\"\nimport { useMutation, 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 { StatusBadge } from \"#orck/admin/components/status-badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport { Input } from \"#orck/admin/components/ui/input\"\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"#orck/admin/components/ui/select\"\nimport { Tabs, TabsList, TabsTrigger } from \"#orck/admin/components/ui/tabs\"\nimport type { PaymentFilters } from \"#orck/admin/lib/api/endpoints\"\nimport type { Payment } from \"#orck/client/generated/wire\"\nimport { downloadCsv } from \"#orck/admin/lib/csv\"\nimport { useUrlCursor } from \"#orck/admin/lib/cursor-pages\"\nimport {\n currencyScale,\n formatNativeAmount,\n formatDate,\n customerName,\n shortId,\n unitsToDecimal,\n} from \"#orck/admin/lib/format\"\n\nconst RAILS = [\"nmi\", \"ccbill\", \"stripe\", \"solana\"]\nconst KINDS = [\n [\"\", \"All\"],\n [\"charge\", \"Charges\"],\n [\"refund\", \"Refunds\"],\n [\"chargeback\", \"Chargebacks\"],\n] as const\n\nconst columns: ColumnDef<Payment, unknown>[] = [\n {\n header: \"Amount\",\n cell: ({ row }) => (\n <span className=\"font-medium tabular-nums\">\n {formatNativeAmount(row.original.amount, row.original.currency)}\n </span>\n ),\n },\n {\n header: \"Status\",\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n { header: \"Kind\", cell: ({ row }) => row.original.kind },\n // Off-rail payments name their channel instead.\n {\n header: \"Rail\",\n cell: ({ row }) => row.original.rail ?? row.original.channel,\n },\n {\n header: \"Payment\",\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {shortId(row.original.id, 16)}\n </span>\n ),\n },\n {\n header: \"Refunded\",\n cell: ({ row }) =>\n row.original.amount_refunded !== \"0\" ? (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatNativeAmount(\n row.original.amount_refunded,\n row.original.currency\n )}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n ),\n },\n {\n header: \"Created\",\n cell: ({ row }) => (\n <span className=\"text-muted-foreground tabular-nums\">\n {formatDate(row.original.created_at)}\n </span>\n ),\n },\n]\n\n// csvAmount exports an exact major-unit decimal; an amount that cannot be\n// represented exactly aborts the export rather than writing a wrong figure.\nfunction csvAmount(amount: string, currency: string): string {\n const scale = currencyScale(currency)\n const decimal = scale === undefined ? null : unitsToDecimal(amount, scale)\n if (decimal === null)\n throw new Error(`${currency} amount ${amount} cannot be exported exactly`)\n return decimal\n}\n\nexport function PaymentsPage() {\n const { toast, toastApiError, adminMutations, adminQueries } =\n useAdminServices()\n\n const { text: adminText } = useAdminUI()\n\n const [params, setParams] = useSearchParams()\n const rail = params.get(\"rail\") ?? \"\"\n const kind = (params.get(\"kind\") ?? \"\") as Payment[\"kind\"] | \"\"\n const userId = params.get(\"customer_id\") ?? \"\"\n const customerLabel = params.get(\"customer\") ?? \"\"\n const paging = useUrlCursor()\n const [input, setInput] = React.useState(\"\")\n const navigate = useNavigate()\n const customerLookup = useMutation(adminMutations.findCustomer())\n const exportPayments = useMutation(adminMutations.exportPayments())\n\n const filters: PaymentFilters = {\n rail: rail || undefined,\n kind: kind || undefined,\n customer_id: userId || undefined,\n }\n const {\n data,\n isPending: loading,\n isFetching,\n } = useQuery(adminQueries.payments(filters, paging.size, paging.cursor))\n\n const setParam = (key: string, value: string) => {\n const p = new URLSearchParams(params)\n if (value) p.set(key, value)\n else p.delete(key)\n p.delete(\"cursor\")\n setParams(p)\n }\n\n // The payments API has no free-text search: resolve the term to a customer,\n // then filter by its id.\n const searchCustomer = async () => {\n const term = input.trim()\n if (!term) return\n try {\n const c = await customerLookup.mutateAsync(term)\n if (!c) {\n toast.info(\"No customer matches\")\n return\n }\n const p = new URLSearchParams(params)\n p.set(\"customer_id\", c.id)\n p.set(\"customer\", customerName(c))\n p.delete(\"cursor\")\n setParams(p)\n setInput(\"\")\n } catch (err) {\n toastApiError(err, \"Search customers\")\n }\n }\n\n const clearCustomer = () => {\n const p = new URLSearchParams(params)\n p.delete(\"customer_id\")\n p.delete(\"customer\")\n p.delete(\"cursor\")\n setParams(p)\n }\n\n const exportCsv = async () => {\n try {\n const rows = await exportPayments.mutateAsync(filters)\n downloadCsv(\n `payments-${new Date().toISOString().slice(0, 10)}.csv`,\n [\n \"id\",\n \"kind\",\n \"status\",\n \"channel\",\n \"amount\",\n \"amount_refunded\",\n \"currency\",\n \"rail\",\n \"customer_id\",\n \"transaction_id\",\n \"created_at\",\n ],\n rows.map((r) => [\n r.id,\n r.kind,\n r.status,\n r.channel,\n csvAmount(r.amount, r.currency),\n csvAmount(r.amount_refunded, r.currency),\n r.currency,\n r.rail,\n r.customer_id,\n r.transaction_id,\n r.created_at,\n ])\n )\n } catch (err) {\n toastApiError(err, \"Export payments\")\n }\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <AdminMessage id={\"Payments\"} />\n </h1>\n <div className=\"flex flex-wrap items-center gap-3\">\n <form\n className=\"relative\"\n aria-busy={customerLookup.isPending}\n onSubmit={(e) => {\n e.preventDefault()\n void searchCustomer()\n }}\n >\n <HugeiconsIcon\n icon={Search01Icon}\n className=\"absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n className=\"w-64 pl-8\"\n placeholder={adminText(\"Search customer email, ref, or id…\")}\n value={input}\n disabled={customerLookup.isPending}\n onChange={(e) => setInput(e.target.value)}\n />\n </form>\n <Select\n items={[\n { value: \"all\", label: \"All rails\" },\n ...RAILS.map((r) => ({ value: r, label: r })),\n ]}\n value={rail || \"all\"}\n onValueChange={(v) => setParam(\"rail\", !v || v === \"all\" ? \"\" : v)}\n >\n <SelectTrigger className=\"w-36\">\n <SelectValue placeholder={adminText(\"Rail\")} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n <AdminMessage id={\"All rails\"} />\n </SelectItem>\n {RAILS.map((r) => (\n <SelectItem key={r} value={r}>\n {r}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Button\n size=\"sm\"\n onClick={exportCsv}\n disabled={exportPayments.isPending || loading || !data?.data.length}\n >\n <HugeiconsIcon icon={Download01Icon} className=\"size-4\" />\n {exportPayments.isPending ? \"Exporting…\" : \"Export CSV\"}\n </Button>\n </div>\n </div>\n\n <Tabs value={kind} onValueChange={(v) => setParam(\"kind\", v ?? \"\")}>\n <TabsList\n variant=\"line\"\n className=\"w-full justify-start gap-6 rounded-none p-0\"\n >\n {KINDS.map(([value, label]) => (\n <TabsTrigger\n key={value}\n value={value}\n className=\"flex-none px-0 after:bg-primary group-data-horizontal/tabs:after:bottom-[-1px]\"\n >\n {label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n\n {userId ? (\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">\n <AdminMessage id={\"Customer\"} />\n </span>\n <span className=\"inline-flex items-center gap-1 rounded-md bg-muted py-0.5 pr-1 pl-2 font-medium\">\n {customerLabel || shortId(userId, 13)}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-5\"\n aria-label={adminText(\"Clear customer filter\")}\n onClick={clearCustomer}\n >\n <HugeiconsIcon icon={Cancel01Icon} className=\"size-3\" />\n </Button>\n </span>\n </div>\n ) : null}\n\n <DataTable\n columns={columns}\n data={data?.data ?? []}\n loading={loading}\n onRowClick={(row) => navigate(`/payments/${row.id}`)}\n emptyMessage=\"No payments 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"],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { E as e, o as t, p as n, r, s as i, w as a } from "./admin-utils-
|
|
2
|
-
import { t as o } from "./admin-button-
|
|
3
|
-
import { s } from "./admin-capabilities-
|
|
1
|
+
import { E as e, o as t, p as n, r, s as i, w as a } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as o } from "./admin-button-Oip73Plq.js";
|
|
3
|
+
import { s } from "./admin-capabilities-BGv7oG8v.js";
|
|
4
4
|
import { o as c, u as l } from "./admin-format-DoohJ7Fg.js";
|
|
5
5
|
import { n as u } from "./admin-confirm-katGq0Qo.js";
|
|
6
|
-
import { a as d, n as f, o as p, r as m, s as h, t as g } from "./admin-table-
|
|
7
|
-
import { t as _ } from "./admin-badge-
|
|
6
|
+
import { a as d, n as f, o as p, r as m, s as h, t as g } from "./admin-table-CWhiCb9d.js";
|
|
7
|
+
import { t as _ } from "./admin-badge-VCGbnfiN.js";
|
|
8
8
|
import { n as v, t as y } from "./admin-price-format-DM1qORWI.js";
|
|
9
|
-
import { a as b, i as x, o as S, r as C, t as w } from "./admin-card-
|
|
10
|
-
import { t as T } from "./admin-price-wizard-
|
|
11
|
-
import { t as E } from "./admin-fact-card-
|
|
9
|
+
import { a as b, i as x, o as S, r as C, t as w } from "./admin-card-DGbi6ZHZ.js";
|
|
10
|
+
import { t as T } from "./admin-price-wizard-ferZSTfO.js";
|
|
11
|
+
import { t as E } from "./admin-fact-card-D6mZgxpN.js";
|
|
12
12
|
import * as D from "react";
|
|
13
13
|
import { useMutation as O, useQuery as k, useQueryClient as A } from "@tanstack/react-query";
|
|
14
14
|
import { Fragment as j, jsx as M, jsxs as N } from "react/jsx-runtime";
|
|
@@ -186,7 +186,7 @@ function q({ price: e, verifying: t, verified: n, onVerify: r }) {
|
|
|
186
186
|
})] });
|
|
187
187
|
}
|
|
188
188
|
function J({ price: e }) {
|
|
189
|
-
let { adminQueries: t } = n(), { data: r, isFetching: i, refetch: s } = k(t.
|
|
189
|
+
let { adminQueries: t } = n(), { data: r, isFetching: i, refetch: s } = k(t.pspRouting(e.id)), c = r?.candidates.filter((e) => !e.skip) ?? [];
|
|
190
190
|
return /* @__PURE__ */ N(w, { children: [/* @__PURE__ */ N(b, {
|
|
191
191
|
className: "flex flex-row items-start justify-between gap-2",
|
|
192
192
|
children: [/* @__PURE__ */ N("div", {
|
|
@@ -194,7 +194,7 @@ function J({ price: e }) {
|
|
|
194
194
|
children: [/* @__PURE__ */ M(S, {
|
|
195
195
|
className: "text-sm",
|
|
196
196
|
children: /* @__PURE__ */ M(a, { id: "Can this be bought?" })
|
|
197
|
-
}), /* @__PURE__ */ M(x, { children: /* @__PURE__ */ M(a, { id: "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
|
|
197
|
+
}), /* @__PURE__ */ M(x, { children: /* @__PURE__ */ M(a, { id: "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." }) })]
|
|
198
198
|
}), /* @__PURE__ */ M(o, {
|
|
199
199
|
variant: "outline",
|
|
200
200
|
size: "sm",
|
|
@@ -479,4 +479,4 @@ function Z({ migrationId: e }) {
|
|
|
479
479
|
//#endregion
|
|
480
480
|
export { X as PriceDetailPage };
|
|
481
481
|
|
|
482
|
-
//# sourceMappingURL=admin-price-detail-
|
|
482
|
+
//# sourceMappingURL=admin-price-detail-BeGDPxKX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-price-detail-BeGDPxKX.js","names":[],"sources":["../src/admin/pages/catalog/psp-links.tsx","../src/admin/pages/catalog/price-detail.tsx"],"sourcesContent":["import { AdminMessage } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { useQuery } from \"@tanstack/react-query\"\n\nimport { Badge } from \"#orck/admin/components/ui/badge\"\nimport { Button } from \"#orck/admin/components/ui/button\"\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"#orck/admin/components/ui/card\"\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"#orck/admin/components/ui/table\"\nimport type { PSPRoutingSkip } from \"#orck/admin/lib/api/types\"\nimport type { PSPLinkState, Price } from \"#orck/client/generated/wire\"\n\n// The catalog is declarative: the provider adapter pushes prices and the\n// read-back reconciliation is alert-only, so this surface displays a price's\n// psp_links and never edits them. It answers two different questions:\n// - Link state (`price.providers`): does OpenRails hold a link for this PSP,\n// and does the remote object still match?\n// - Purchase readiness (the routing preview): would a real purchase land\n// here now? A linked price can still be unroutable (PSP unarmed,\n// credentials missing).\n\n// SKIP_LABELS renders the routing skip vocabulary for operators. Keep the keys\n// in lockstep with internal/db/models/order_attempt.go.\nconst SKIP_LABELS: Record<PSPRoutingSkip, string> = {\n unknown_selector: \"That name matches no provider you have set up.\",\n ambiguous_selector:\n \"More than one provider on this rail is set up. Name the provider rather than the rail.\",\n not_armed: \"This provider is not set up here, or it was archived.\",\n credentials_missing:\n \"The provider is set up, but the credentials it needs are missing.\",\n link_missing: \"This price has not been sent to the provider yet.\",\n mode_unsupported:\n \"This provider cannot take this kind of payment (one-off or recurring).\",\n posture_disarmed:\n \"The provider's credentials failed their test-mode check, so it is switched off.\",\n service_unavailable: \"The connection to this provider is not running.\",\n resolve_failed: \"The provider could not be worked out at the time of asking.\",\n}\n\n// The engine names each outcome for its own logs. These are the same outcomes\n// as a sentence you can act on.\nconst SKIP_HEADLINES: Record<PSPRoutingSkip, string> = {\n unknown_selector: \"unknown provider\",\n ambiguous_selector: \"more than one match\",\n not_armed: \"not set up\",\n credentials_missing: \"credentials missing\",\n link_missing: \"not sent to provider\",\n mode_unsupported: \"cannot take this payment\",\n posture_disarmed: \"credentials failed check\",\n service_unavailable: \"connection not running\",\n resolve_failed: \"could not be worked out\",\n}\n\nfunction skipHeadline(skip?: string | null): string {\n if (!skip) return \"ready\"\n return SKIP_HEADLINES[skip as PSPRoutingSkip] ?? skip\n}\n\nfunction skipLabel(skip?: string | null) {\n if (!skip) return \"\"\n return SKIP_LABELS[skip as PSPRoutingSkip] ?? skip\n}\n\nconst OK_BADGE = \"bg-settled-surface text-settled\"\nconst WARN_BADGE = \"bg-held-surface text-held\"\nconst BAD_BADGE = \"bg-failed-surface text-failed\"\n\nfunction linkStatusClass(status: PSPLinkState[\"status\"]) {\n if (status === \"linked\") return OK_BADGE\n if (status === \"error\") return BAD_BADGE\n return WARN_BADGE\n}\n\n// syncStatusClass leaves \"unknown\" neutral, not a warning: nobody has checked\n// yet.\nfunction syncStatusClass(sync?: string) {\n switch (sync) {\n case \"in_sync\":\n return OK_BADGE\n case \"drifted\":\n case \"missing\":\n return BAD_BADGE\n case \"never_synced\":\n case \"sync_disabled\":\n return WARN_BADGE\n default:\n return \"\"\n }\n}\n\n// LINK_ID_ORDER puts the identifying fields first; anything else the adapter\n// stored follows in sorted order. `rail` is pulled out into its own column.\nconst LINK_ID_ORDER = [\n \"price_id\",\n \"product_id\",\n \"plan_id\",\n \"form_name\",\n \"flex_id\",\n \"recurring_billing_option_id\",\n \"lookup_key\",\n \"provider\",\n]\n\nfunction linkEntries(ids?: Record<string, string> | null) {\n const rest = Object.entries(ids ?? {}).filter(\n ([k, v]) => k !== \"rail\" && v !== \"\"\n )\n rest.sort(([a], [b]) => {\n const ia = LINK_ID_ORDER.indexOf(a)\n const ib = LINK_ID_ORDER.indexOf(b)\n if (ia !== ib)\n return (\n (ia < 0 ? LINK_ID_ORDER.length : ia) -\n (ib < 0 ? LINK_ID_ORDER.length : ib)\n )\n return a.localeCompare(b)\n })\n return rest\n}\n\nexport function PSPLinksCard({\n price,\n verifying,\n verified,\n onVerify,\n}: {\n price: Price\n verifying: boolean\n verified: boolean\n onVerify: () => void\n}) {\n const links = Object.entries(price.psps ?? {}).sort(([a], [b]) =>\n a.localeCompare(b)\n )\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-start justify-between gap-2\">\n <div className=\"grid gap-1\">\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"Payment providers\"} />\n </CardTitle>\n <CardDescription>\n <AdminMessage\n id={\n \"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.\"\n }\n />\n </CardDescription>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={verifying || !links.length}\n onClick={onVerify}\n >\n {verifying ? \"Verifying…\" : \"Verify\"}\n </Button>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-3\">\n {!links.length ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage\n id={\n \"This price has not been sent to any provider, so nobody can be charged for it yet.\"\n }\n />\n </p>\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Provider\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Rail\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Sent\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Still matches\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Their reference\"} />\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {links.map(([psp, state]) => (\n <TableRow key={psp}>\n <TableCell className=\"font-mono text-xs\">{psp}</TableCell>\n <TableCell className=\"text-xs\">\n {state.ids?.rail ?? \"—\"}\n </TableCell>\n <TableCell>\n <Badge\n variant=\"secondary\"\n className={linkStatusClass(state.status)}\n >\n {state.status}\n </Badge>\n {state.message && (\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">\n {state.message}\n </p>\n )}\n </TableCell>\n <TableCell>\n <Badge\n variant=\"secondary\"\n className={syncStatusClass(state.sync_status)}\n >\n {state.sync_status ?? \"unknown\"}\n </Badge>\n {state.drift?.map((d) => (\n <p\n key={d.field}\n className=\"mt-1 text-xs text-muted-foreground\"\n >\n {d.field}\n <AdminMessage id={\": yours \"} />\n {d.openrails_value}\n <AdminMessage id={\" · theirs\"} /> {d.remote_value}\n </p>\n ))}\n </TableCell>\n <TableCell className=\"font-mono text-xs\">\n {linkEntries(state.ids).length ? (\n <div className=\"grid gap-0.5\">\n {linkEntries(state.ids).map(([k, v]) => (\n <span key={k}>\n {k}={v}\n </span>\n ))}\n </div>\n ) : (\n \"—\"\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n {!!price.pending_manual_actions?.length && (\n <div className=\"border-held/40 rounded-md border p-3 text-xs\">\n {price.pending_manual_actions.map((a) => (\n <p key={`${a.psp}-${a.action}`}>\n <span className=\"font-mono\">{a.psp}</span>: {a.hint || a.action}\n </p>\n ))}\n </div>\n )}\n {!verified && !!links.length && (\n <p className=\"text-xs text-muted-foreground\">\n <AdminMessage\n id={\n \"Nothing is claimed about the providers' copies until you press Verify.\"\n }\n />\n </p>\n )}\n </CardContent>\n </Card>\n )\n}\n\n// PSPReadinessCard answers \"can someone buy this right now, and if not,\n// why?\" with the routing preview, so the console and purchase never disagree.\nexport function PSPReadinessCard({ price }: { price: Price }) {\n const { adminQueries } = useAdminServices()\n\n const {\n data: decision,\n isFetching: busy,\n refetch: reload,\n } = useQuery(adminQueries.pspRouting(price.id))\n\n const eligible = decision?.candidates.filter((c) => !c.skip) ?? []\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-start justify-between gap-2\">\n <div className=\"grid gap-1\">\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"Can this be bought?\"} />\n </CardTitle>\n <CardDescription>\n <AdminMessage\n id={\n \"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.\"\n }\n />\n </CardDescription>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={busy}\n onClick={() => void reload()}\n >\n {busy ? \"Checking…\" : \"Re-check\"}\n </Button>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-3\">\n {!decision ? (\n <p className=\"text-sm text-muted-foreground\">\n {busy ? \"Checking…\" : \"This check could not be run.\"}\n </p>\n ) : (\n <>\n <p className=\"text-sm\">\n {decision.psp ? (\n <>\n <AdminMessage id={\"Money for this price would go to\"} />{\" \"}\n <span className=\"font-medium\">{decision.psp}</span>\n {decision.rail && (\n <>\n <AdminMessage id={\" on \"} />\n {decision.rail}\n </>\n )}\n .\n </>\n ) : (\n <span className=\"text-held\">\n <AdminMessage\n id={\n \"No provider can take this payment, so nobody can buy this price yet.\"\n }\n />\n </span>\n )}\n </p>\n {!decision.candidates.length ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"There were no providers to consider.\"} />\n </p>\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Provider\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Rail\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Outcome\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Why\"} />\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {decision.candidates.map((c) => (\n <TableRow key={c.psp}>\n <TableCell className=\"font-mono text-xs\">\n {c.psp}\n {c.psp === decision.psp && (\n <Badge\n variant=\"secondary\"\n className={`ml-2 ${OK_BADGE}`}\n >\n <AdminMessage id={\"selected\"} />\n </Badge>\n )}\n </TableCell>\n <TableCell className=\"text-xs\">\n {c.rail || \"—\"}\n </TableCell>\n <TableCell>\n <Badge\n variant=\"secondary\"\n className={c.skip ? WARN_BADGE : OK_BADGE}\n >\n {skipHeadline(c.skip)}\n </Badge>\n </TableCell>\n <TableCell className=\"text-xs text-muted-foreground\">\n {skipLabel(c.skip)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n {!!decision.candidates.length && eligible.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n <AdminMessage\n id={\n '\"Not sent to provider\" is fixed by publishing the catalog. Everything else is fixed under Settings, Payment providers.'\n }\n />\n </p>\n )}\n </>\n )}\n </CardContent>\n </Card>\n )\n}\n","import { AdminMessage, useAdminUI } from \"#orck/admin/ui-context\"\nimport { useAdminServices } from \"#orck/admin/context\"\nimport { HugeiconsIcon } from \"@hugeicons/react\"\nimport { ArrowLeft01Icon } from \"@hugeicons/core-free-icons\"\nimport * as React from \"react\"\nimport { Link, useLocation, useNavigate } from \"#orck/admin/router\"\n\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\"\n\nimport { Fact } from \"#orck/admin/components/fact-card\"\nimport { Badge } from \"#orck/admin/components/ui/badge\"\nimport { useConfirm } from \"#orck/admin/lib/confirm\"\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 Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"#orck/admin/components/ui/table\"\nimport { formatDate, shortId } from \"#orck/admin/lib/format\"\n\nimport {\n priceAmountLabel,\n priceIntervalLabel,\n} from \"#orck/admin/pages/catalog/price-format\"\nimport { PriceChangeWizard } from \"#orck/admin/pages/catalog/price-wizard\"\nimport {\n PSPReadinessCard,\n PSPLinksCard,\n} from \"#orck/admin/pages/catalog/psp-links\"\nimport { useCatalogWrites } from \"#orck/admin/lib/capabilities\"\n\n// A price ID can contain its own percent-encoded key bytes. Router params\n// decode an inner %2F again; decode the original URL segment exactly once.\nfunction priceIDFromPath(pathname: string): string {\n const segment = pathname.replace(/\\/+$/, \"\").split(\"/\").at(-1) ?? \"\"\n try {\n return decodeURIComponent(segment)\n } catch {\n return \"\"\n }\n}\n\n// PriceDetailPage (#777): the version chain (from the #774 pointer-movement\n// log, with dates) and any pending scheduled migration (progress + cancel)\n// for one price key — the wizard's Step 1 entry point (\"Change price\") also\n// lives here alongside the catalog list row.\nexport function PriceDetailPage() {\n const { text: adminText } = useAdminUI()\n\n const { adminQueries } = useAdminServices()\n\n const id = priceIDFromPath(useLocation().pathname)\n const writesAllowed = useCatalogWrites()\n const navigate = useNavigate()\n // verify (or#812) is opt-in: it makes GET price perform a live retrieve\n // against every attached provider, which is a network round trip per PSP.\n const [verify, setVerify] = React.useState(false)\n const {\n data: price,\n isPending: loading,\n isFetching,\n refetch: reload,\n } = useQuery(adminQueries.price(id, { verify, errorAction: \"Load price\" }))\n const { data: product } = useQuery(adminQueries.product(price?.product_id))\n const { data: history } = useQuery(adminQueries.priceHistory(price?.id))\n const { data: migrations } = useQuery(\n adminQueries.priceMigrations(product?.key, price?.key)\n )\n const latestBatch = migrations?.data?.[0]\n\n if (!id)\n return (\n <p role=\"alert\" className=\"text-sm text-muted-foreground\">\n Invalid price URL.\n </p>\n )\n\n // Only the FIRST load blanks the page; a verify refetch keeps the rendered\n // price in place so the button can show its own in-flight state.\n if (!price)\n return (\n <p className=\"text-sm text-muted-foreground\">\n {loading ? \"Loading…\" : \"Price not found.\"}\n </p>\n )\n\n const isPending = !!latestBatch && latestBatch.scheduled > 0\n\n return (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\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 <div>\n <h2 className=\"flex items-center gap-2 text-sm\">\n {price.id}\n {price.archived && (\n <Badge variant=\"secondary\">\n <AdminMessage id={\"archived\"} />\n </Badge>\n )}\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {product?.display_name}\n </p>\n </div>\n <div className=\"ml-auto\">\n {writesAllowed && (\n <PriceChangeWizard\n price={price}\n productName={product?.display_name ?? \"…\"}\n productKey={product?.key}\n />\n )}\n </div>\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Fact label={adminText(\"Product\")}>\n <Link className=\"underline-offset-2 hover:underline\" to={`/catalog`}>\n {product?.display_name ?? shortId(price.product_id, 13)}\n </Link>\n </Fact>\n <Fact label={adminText(\"Amount\")}>{priceAmountLabel(price)}</Fact>\n <Fact label={adminText(\"Renews\")}>\n {price.currency.toUpperCase()} · {priceIntervalLabel(price)}\n </Fact>\n <Fact label={adminText(\"Created\")}>{formatDate(price.created_at)}</Fact>\n </div>\n\n <PSPLinksCard\n price={price}\n verifying={verify && isFetching}\n verified={verify}\n onVerify={() => (verify ? void reload() : setVerify(true))}\n />\n\n <PSPReadinessCard price={price} />\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">\n <AdminMessage id={\"Price history\"} />\n </CardTitle>\n </CardHeader>\n <CardContent>\n {!history?.data?.length ? (\n <p className=\"text-sm text-muted-foreground\">\n <AdminMessage id={\"No history yet.\"} />\n </p>\n ) : (\n <Table>\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Amount\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Since\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"State\"} />\n </TableHead>\n <TableHead className=\"text-muted-foreground\">\n <AdminMessage id={\"Price\"} />\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {history.data.map((entry) => (\n <TableRow key={`${entry.price.id}-${entry.effective_at}`}>\n <TableCell>{priceAmountLabel(entry.price)}</TableCell>\n <TableCell>{formatDate(entry.effective_at)}</TableCell>\n <TableCell>\n {entry.archived ? (\n <Badge variant=\"secondary\">\n <AdminMessage id={\"retired\"} />\n </Badge>\n ) : (\n <Badge className=\"bg-settled-surface text-settled\">\n <AdminMessage id={\"offered\"} />\n </Badge>\n )}\n </TableCell>\n <TableCell>\n <Link\n className=\"text-xs underline-offset-2 hover:underline\"\n to={`/catalog/prices/${encodeURIComponent(entry.price.id)}`}\n title={entry.price.id}\n >\n {entry.price.id}\n </Link>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </CardContent>\n </Card>\n\n {latestBatch && (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between gap-2\">\n <CardTitle className=\"text-sm\">\n {isPending\n ? \"Moving customers to the new price\"\n : \"Last move to a new price\"}\n </CardTitle>\n {isPending && (\n <CancelMigrationButton migrationId={latestBatch.id} />\n )}\n </CardHeader>\n <CardContent className=\"flex flex-col gap-2 text-sm\">\n <p>\n {latestBatch.applied}\n <AdminMessage id={\" of\"} />{\" \"}\n {latestBatch.applied +\n latestBatch.scheduled +\n latestBatch.canceled}{\" \"}\n <AdminMessage id={\"moved\"} />\n {latestBatch.scheduled > 0 &&\n ` · ${latestBatch.scheduled} still scheduled`}\n {\" · effective\"}\n {formatDate(latestBatch.effective_at)}\n </p>\n {latestBatch.skipped > 0 && (\n <p className=\"text-xs text-muted-foreground\">\n {latestBatch.skipped}\n <AdminMessage id={\" subscription\"} />\n {latestBatch.skipped === 1 ? \" was\" : \"s were\"}\n <AdminMessage\n id={\n \" left alone because another change was already scheduled for them.\"\n }\n />\n </p>\n )}\n </CardContent>\n </Card>\n )}\n </div>\n )\n}\n\nfunction CancelMigrationButton({ migrationId }: { migrationId: string }) {\n const { toast, toastApiError, adminMutations } = useAdminServices()\n\n const queryClient = useQueryClient()\n const cancelBatch = useMutation(\n adminMutations.cancelPriceMigration(queryClient)\n )\n const confirm = useConfirm()\n return (\n <Button\n variant=\"destructive\"\n size=\"sm\"\n disabled={cancelBatch.isPending}\n onClick={async () => {\n const canceling = await confirm({\n title: \"Cancel this migration?\",\n description:\n \"Subscribers not yet moved stay on their current price. Those already moved stay moved.\",\n confirmLabel: \"Cancel migration\",\n cancelLabel: \"Keep migrating\",\n tone: \"destructive\",\n })\n if (!canceling) return\n try {\n const result = await cancelBatch.mutateAsync(migrationId)\n toast.success(\n `Canceled ${result.canceled} pending move${result.canceled === 1 ? \"\" : \"s\"}. Already-migrated subscribers stay migrated.`\n )\n const release = result.rail_release_required.length\n if (release > 0)\n toast.warning(\n `${release} Stripe subscription${release === 1 ? \" still carries\" : \"s still carry\"} the move as a Stripe subscription schedule: release it in Stripe, or the price changes at period end.`\n )\n } catch (err) {\n toastApiError(err, \"Cancel migration\")\n }\n }}\n >\n {cancelBatch.isPending ? \"Canceling…\" : \"Cancel migration\"}\n </Button>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { E as e, p as t, w as n } from "./admin-utils-
|
|
2
|
-
import { t as r } from "./admin-button-
|
|
3
|
-
import { t as i } from "./admin-input-
|
|
1
|
+
import { E as e, p as t, w as n } from "./admin-utils-DnVY5fYd.js";
|
|
2
|
+
import { t as r } from "./admin-button-Oip73Plq.js";
|
|
3
|
+
import { t as i } from "./admin-input-DO5lvCLL.js";
|
|
4
4
|
import { c as a, l as o, s } from "./admin-format-DoohJ7Fg.js";
|
|
5
5
|
import { t as c } from "./admin-form-field-errors-hbUMIriS.js";
|
|
6
|
-
import { t as l } from "./admin-badge-
|
|
7
|
-
import { a as u, i as d, n as f, o as p, r as m, s as h, t as g } from "./admin-dialog-
|
|
8
|
-
import { t as _ } from "./admin-label-
|
|
6
|
+
import { t as l } from "./admin-badge-VCGbnfiN.js";
|
|
7
|
+
import { a as u, i as d, n as f, o as p, r as m, s as h, t as g } from "./admin-dialog-Ffx95AIT.js";
|
|
8
|
+
import { t as _ } from "./admin-label-BzJpr3lg.js";
|
|
9
9
|
import { n as v } from "./admin-dialog-width-BPrgdYlj.js";
|
|
10
10
|
import { n as y } from "./admin-price-format-DM1qORWI.js";
|
|
11
11
|
import * as b from "react";
|
|
@@ -354,4 +354,4 @@ function P({ price: o, productName: A, productKey: P, draft: F, onDone: re }) {
|
|
|
354
354
|
//#endregion
|
|
355
355
|
export { P as t };
|
|
356
356
|
|
|
357
|
-
//# sourceMappingURL=admin-price-wizard-
|
|
357
|
+
//# sourceMappingURL=admin-price-wizard-ferZSTfO.js.map
|